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