1 /* 2 * Copyright 2017 Frank Hunleth 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef BLOCK_CACHE_H 18 #define BLOCK_CACHE_H 19 20 #include "config.h" 21 #include "util.h" 22 23 // Don't use pthreads on Windows yet. 24 #ifndef _WIN32 25 #if HAVE_PTHREAD 26 #define USE_PTHREADS 1 27 #endif 28 #endif 29 30 #if USE_PTHREADS 31 #include <pthread.h> 32 #endif 33 34 // The segment size defines the minimum read/write size 35 // actually made to the output. Additionally, all reads and 36 // writes will be aligned to that size. 37 #define BLOCK_CACHE_SEGMENT_SIZE (128*1024) // This is also the read/write write size 38 #define BLOCK_CACHE_NUM_SEGMENTS 64 // 8 MB cache 39 #define BLOCK_CACHE_BLOCKS_PER_SEGMENT (BLOCK_CACHE_SEGMENT_SIZE / FWUP_BLOCK_SIZE) 40 #define BLOCK_CACHE_SEGMENT_MASK (~(BLOCK_CACHE_SEGMENT_SIZE - 1)) 41 42 struct block_cache_segment { 43 bool in_use; 44 45 // The data in this segment. 46 uint8_t *data; 47 48 // Where this segment is located 49 off_t offset; 50 51 // "timestamp" for computing least recently used 52 uint32_t last_access; 53 54 // Set to true if all of the data written to this segment 55 // has been streamed. If true and the entire segment is marked 56 // dirty, then it should be written to the target asap so that 57 // the actual writes can start. 58 bool streamed; 59 60 // Bit fields for determining whether blocks inside the 61 // segment are valid (hold the most up-to-date data) and/or 62 // dirty (need to be written back to the target image). 63 // (2 bits of flags in a uint8_t) 64 uint8_t flags[BLOCK_CACHE_BLOCKS_PER_SEGMENT * 2 / 8]; 65 }; 66 67 struct block_cache { 68 int fd; 69 70 // Read everything back after its written 71 bool verify_writes; 72 73 // Counter for maintaining LRU 74 uint32_t timestamp; 75 76 // All of the cached segments 77 struct block_cache_segment segments[BLOCK_CACHE_NUM_SEGMENTS]; 78 79 // Temporary buffer for reading segments that are partially valid 80 uint8_t *read_temp; 81 82 // Temporary buffer for checking that writes worked 83 uint8_t *verify_temp; 84 85 // Track "trimmed" segments in a bitfield. One bit per segment. 86 // E.g., 128K/bit -> 1M takes represented in 1 byte -> 1G in 1 KB, etc. 87 size_t trimmed_len; 88 off_t trimmed_end_offset; 89 uint8_t *trimmed; 90 bool trimmed_remainder; // true if segments after end of bitfield are trimmed 91 bool hw_trim_enabled; 92 93 // This tracks the number of blocks on the destination 94 uint32_t num_blocks; 95 96 // Asynchronous writes 97 #if USE_PTHREADS 98 pthread_t writer_thread; 99 pthread_mutex_t mutex; 100 pthread_cond_t cond; 101 uint8_t *thread_verify_temp; 102 103 volatile bool running; 104 volatile struct block_cache_segment *seg_to_write; 105 volatile off_t bad_offset; // set if pwrite fails asynchronously 106 #endif 107 }; 108 109 int block_cache_init(struct block_cache *bc, int fd, off_t end_offset, bool enable_trim, bool verify_writes); 110 int block_cache_trim(struct block_cache *bc, off_t offset, off_t count, bool hwtrim); 111 int block_cache_trim_after(struct block_cache *bc, off_t offset, bool hwtrim); 112 int block_cache_pwrite(struct block_cache *bc, const void *buf, size_t count, off_t offset, bool streamed); 113 int block_cache_pread(struct block_cache *bc, void *buf, size_t count, off_t offset); 114 int block_cache_flush(struct block_cache *bc); 115 void block_cache_reset(struct block_cache *bc); 116 int block_cache_free(struct block_cache *bc); 117 118 #endif // BLOCK_CACHE_H 119