Based on kernel version 4.16.1. Page generated on 2018-04-09 11:53 EST.
1 BTT - Block Translation Table 2 ============================= 3 4 5 1. Introduction 6 --------------- 7 8 Persistent memory based storage is able to perform IO at byte (or more 9 accurately, cache line) granularity. However, we often want to expose such 10 storage as traditional block devices. The block drivers for persistent memory 11 will do exactly this. However, they do not provide any atomicity guarantees. 12 Traditional SSDs typically provide protection against torn sectors in hardware, 13 using stored energy in capacitors to complete in-flight block writes, or perhaps 14 in firmware. We don't have this luxury with persistent memory - if a write is in 15 progress, and we experience a power failure, the block will contain a mix of old 16 and new data. Applications may not be prepared to handle such a scenario. 17 18 The Block Translation Table (BTT) provides atomic sector update semantics for 19 persistent memory devices, so that applications that rely on sector writes not 20 being torn can continue to do so. The BTT manifests itself as a stacked block 21 device, and reserves a portion of the underlying storage for its metadata. At 22 the heart of it, is an indirection table that re-maps all the blocks on the 23 volume. It can be thought of as an extremely simple file system that only 24 provides atomic sector updates. 25 26 27 2. Static Layout 28 ---------------- 29 30 The underlying storage on which a BTT can be laid out is not limited in any way. 31 The BTT, however, splits the available space into chunks of up to 512 GiB, 32 called "Arenas". 33 34 Each arena follows the same layout for its metadata, and all references in an 35 arena are internal to it (with the exception of one field that points to the 36 next arena). The following depicts the "On-disk" metadata layout: 37 38 39 Backing Store +-------> Arena 40 +---------------+ | +------------------+ 41 | | | | Arena info block | 42 | Arena 0 +---+ | 4K | 43 | 512G | +------------------+ 44 | | | | 45 +---------------+ | | 46 | | | | 47 | Arena 1 | | Data Blocks | 48 | 512G | | | 49 | | | | 50 +---------------+ | | 51 | . | | | 52 | . | | | 53 | . | | | 54 | | | | 55 | | | | 56 +---------------+ +------------------+ 57 | | 58 | BTT Map | 59 | | 60 | | 61 +------------------+ 62 | | 63 | BTT Flog | 64 | | 65 +------------------+ 66 | Info block copy | 67 | 4K | 68 +------------------+ 69 70 71 3. Theory of Operation 72 ---------------------- 73 74 75 a. The BTT Map 76 -------------- 77 78 The map is a simple lookup/indirection table that maps an LBA to an internal 79 block. Each map entry is 32 bits. The two most significant bits are special 80 flags, and the remaining form the internal block number. 81 82 Bit Description 83 31 - 30 : Error and Zero flags - Used in the following way: 84 Bit Description 85 31 30 86 ----------------------------------------------------------------------- 87 00 Initial state. Reads return zeroes; Premap = Postmap 88 01 Zero state: Reads return zeroes 89 10 Error state: Reads fail; Writes clear 'E' bit 90 11 Normal Block – has valid postmap 91 92 93 29 - 0 : Mappings to internal 'postmap' blocks 94 95 96 Some of the terminology that will be subsequently used: 97 98 External LBA : LBA as made visible to upper layers. 99 ABA : Arena Block Address - Block offset/number within an arena 100 Premap ABA : The block offset into an arena, which was decided upon by range 101 checking the External LBA 102 Postmap ABA : The block number in the "Data Blocks" area obtained after 103 indirection from the map 104 nfree : The number of free blocks that are maintained at any given time. 105 This is the number of concurrent writes that can happen to the 106 arena. 107 108 109 For example, after adding a BTT, we surface a disk of 1024G. We get a read for 110 the external LBA at 768G. This falls into the second arena, and of the 512G 111 worth of blocks that this arena contributes, this block is at 256G. Thus, the 112 premap ABA is 256G. We now refer to the map, and find out the mapping for block 113 'X' (256G) points to block 'Y', say '64'. Thus the postmap ABA is 64. 114 115 116 b. The BTT Flog 117 --------------- 118 119 The BTT provides sector atomicity by making every write an "allocating write", 120 i.e. Every write goes to a "free" block. A running list of free blocks is 121 maintained in the form of the BTT flog. 'Flog' is a combination of the words 122 "free list" and "log". The flog contains 'nfree' entries, and an entry contains: 123 124 lba : The premap ABA that is being written to 125 old_map : The old postmap ABA - after 'this' write completes, this will be a 126 free block. 127 new_map : The new postmap ABA. The map will up updated to reflect this 128 lba->postmap_aba mapping, but we log it here in case we have to 129 recover. 130 seq : Sequence number to mark which of the 2 sections of this flog entry is 131 valid/newest. It cycles between 01->10->11->01 (binary) under normal 132 operation, with 00 indicating an uninitialized state. 133 lba' : alternate lba entry 134 old_map': alternate old postmap entry 135 new_map': alternate new postmap entry 136 seq' : alternate sequence number. 137 138 Each of the above fields is 32-bit, making one entry 32 bytes. Entries are also 139 padded to 64 bytes to avoid cache line sharing or aliasing. Flog updates are 140 done such that for any entry being written, it: 141 a. overwrites the 'old' section in the entry based on sequence numbers 142 b. writes the 'new' section such that the sequence number is written last. 143 144 145 c. The concept of lanes 146 ----------------------- 147 148 While 'nfree' describes the number of concurrent IOs an arena can process 149 concurrently, 'nlanes' is the number of IOs the BTT device as a whole can 150 process. 151 nlanes = min(nfree, num_cpus) 152 A lane number is obtained at the start of any IO, and is used for indexing into 153 all the on-disk and in-memory data structures for the duration of the IO. If 154 there are more CPUs than the max number of available lanes, than lanes are 155 protected by spinlocks. 156 157 158 d. In-memory data structure: Read Tracking Table (RTT) 159 ------------------------------------------------------ 160 161 Consider a case where we have two threads, one doing reads and the other, 162 writes. We can hit a condition where the writer thread grabs a free block to do 163 a new IO, but the (slow) reader thread is still reading from it. In other words, 164 the reader consulted a map entry, and started reading the corresponding block. A 165 writer started writing to the same external LBA, and finished the write updating 166 the map for that external LBA to point to its new postmap ABA. At this point the 167 internal, postmap block that the reader is (still) reading has been inserted 168 into the list of free blocks. If another write comes in for the same LBA, it can 169 grab this free block, and start writing to it, causing the reader to read 170 incorrect data. To prevent this, we introduce the RTT. 171 172 The RTT is a simple, per arena table with 'nfree' entries. Every reader inserts 173 into rtt[lane_number], the postmap ABA it is reading, and clears it after the 174 read is complete. Every writer thread, after grabbing a free block, checks the 175 RTT for its presence. If the postmap free block is in the RTT, it waits till the 176 reader clears the RTT entry, and only then starts writing to it. 177 178 179 e. In-memory data structure: map locks 180 -------------------------------------- 181 182 Consider a case where two writer threads are writing to the same LBA. There can 183 be a race in the following sequence of steps: 184 185 free[lane] = map[premap_aba] 186 map[premap_aba] = postmap_aba 187 188 Both threads can update their respective free[lane] with the same old, freed 189 postmap_aba. This has made the layout inconsistent by losing a free entry, and 190 at the same time, duplicating another free entry for two lanes. 191 192 To solve this, we could have a single map lock (per arena) that has to be taken 193 before performing the above sequence, but we feel that could be too contentious. 194 Instead we use an array of (nfree) map_locks that is indexed by 195 (premap_aba modulo nfree). 196 197 198 f. Reconstruction from the Flog 199 ------------------------------- 200 201 On startup, we analyze the BTT flog to create our list of free blocks. We walk 202 through all the entries, and for each lane, of the set of two possible 203 'sections', we always look at the most recent one only (based on the sequence 204 number). The reconstruction rules/steps are simple: 205 - Read map[log_entry.lba]. 206 - If log_entry.new matches the map entry, then log_entry.old is free. 207 - If log_entry.new does not match the map entry, then log_entry.new is free. 208 (This case can only be caused by power-fails/unsafe shutdowns) 209 210 211 g. Summarizing - Read and Write flows 212 ------------------------------------- 213 214 Read: 215 216 1. Convert external LBA to arena number + pre-map ABA 217 2. Get a lane (and take lane_lock) 218 3. Read map to get the entry for this pre-map ABA 219 4. Enter post-map ABA into RTT[lane] 220 5. If TRIM flag set in map, return zeroes, and end IO (go to step 8) 221 6. If ERROR flag set in map, end IO with EIO (go to step 8) 222 7. Read data from this block 223 8. Remove post-map ABA entry from RTT[lane] 224 9. Release lane (and lane_lock) 225 226 Write: 227 228 1. Convert external LBA to Arena number + pre-map ABA 229 2. Get a lane (and take lane_lock) 230 3. Use lane to index into in-memory free list and obtain a new block, next flog 231 index, next sequence number 232 4. Scan the RTT to check if free block is present, and spin/wait if it is. 233 5. Write data to this free block 234 6. Read map to get the existing post-map ABA entry for this pre-map ABA 235 7. Write flog entry: [premap_aba / old postmap_aba / new postmap_aba / seq_num] 236 8. Write new post-map ABA into map. 237 9. Write old post-map entry into the free list 238 10. Calculate next sequence number and write into the free list entry 239 11. Release lane (and lane_lock) 240 241 242 4. Error Handling 243 ================= 244 245 An arena would be in an error state if any of the metadata is corrupted 246 irrecoverably, either due to a bug or a media error. The following conditions 247 indicate an error: 248 - Info block checksum does not match (and recovering from the copy also fails) 249 - All internal available blocks are not uniquely and entirely addressed by the 250 sum of mapped blocks and free blocks (from the BTT flog). 251 - Rebuilding free list from the flog reveals missing/duplicate/impossible 252 entries 253 - A map entry is out of bounds 254 255 If any of these error conditions are encountered, the arena is put into a read 256 only state using a flag in the info block. 257 258 259 5. Usage 260 ======== 261 262 The BTT can be set up on any disk (namespace) exposed by the libnvdimm subsystem 263 (pmem, or blk mode). The easiest way to set up such a namespace is using the 264 'ndctl' utility [1]: 265 266 For example, the ndctl command line to setup a btt with a 4k sector size is: 267 268 ndctl create-namespace -f -e namespace0.0 -m sector -l 4k 269 270 See ndctl create-namespace --help for more options. 271 272 [1]: https://github.com/pmem/ndctl