5sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget)/translations/zh_CN/driver-api/nvdimm/bttmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget)/translations/zh_TW/driver-api/nvdimm/bttmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget)/translations/it_IT/driver-api/nvdimm/bttmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget)/translations/ja_JP/driver-api/nvdimm/bttmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget)/translations/ko_KR/driver-api/nvdimm/bttmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget)/translations/sp_SP/driver-api/nvdimm/bttmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhsection)}(hhh](htitle)}(hBTT - Block Translation Tableh]hBTT - Block Translation Table}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhC/var/lib/git/docbuild/linux/Documentation/driver-api/nvdimm/btt.rsthKubh)}(hhh](h)}(h1. Introductionh]h1. Introduction}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh paragraph)}(hXPersistent memory based storage is able to perform IO at byte (or more accurately, cache line) granularity. However, we often want to expose such storage as traditional block devices. The block drivers for persistent memory will do exactly this. However, they do not provide any atomicity guarantees. Traditional SSDs typically provide protection against torn sectors in hardware, using stored energy in capacitors to complete in-flight block writes, or perhaps in firmware. We don't have this luxury with persistent memory - if a write is in progress, and we experience a power failure, the block will contain a mix of old and new data. Applications may not be prepared to handle such a scenario.h]hXPersistent memory based storage is able to perform IO at byte (or more accurately, cache line) granularity. However, we often want to expose such storage as traditional block devices. The block drivers for persistent memory will do exactly this. However, they do not provide any atomicity guarantees. Traditional SSDs typically provide protection against torn sectors in hardware, using stored energy in capacitors to complete in-flight block writes, or perhaps in firmware. We don’t have this luxury with persistent memory - if a write is in progress, and we experience a power failure, the block will contain a mix of old and new data. Applications may not be prepared to handle such a scenario.}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK hhhhubh)}(hXThe Block Translation Table (BTT) provides atomic sector update semantics for persistent memory devices, so that applications that rely on sector writes not being torn can continue to do so. The BTT manifests itself as a stacked block device, and reserves a portion of the underlying storage for its metadata. At the heart of it, is an indirection table that re-maps all the blocks on the volume. It can be thought of as an extremely simple file system that only provides atomic sector updates.h]hXThe Block Translation Table (BTT) provides atomic sector update semantics for persistent memory devices, so that applications that rely on sector writes not being torn can continue to do so. The BTT manifests itself as a stacked block device, and reserves a portion of the underlying storage for its metadata. At the heart of it, is an indirection table that re-maps all the blocks on the volume. It can be thought of as an extremely simple file system that only provides atomic sector updates.}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubeh}(h] introductionah ]h"]1. introductionah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h2. Static Layouth]h2. Static Layout}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh)}(hThe underlying storage on which a BTT can be laid out is not limited in any way. The BTT, however, splits the available space into chunks of up to 512 GiB, called "Arenas".h]hThe underlying storage on which a BTT can be laid out is not limited in any way. The BTT, however, splits the available space into chunks of up to 512 GiB, called “Arenas”.}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hEach arena follows the same layout for its metadata, and all references in an arena are internal to it (with the exception of one field that points to the next arena). The following depicts the "On-disk" metadata layout::h]hEach arena follows the same layout for its metadata, and all references in an arena are internal to it (with the exception of one field that points to the next arena). The following depicts the “On-disk” metadata layout:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK#hhhhubh literal_block)}(hX= Backing Store +-------> Arena +---------------+ | +------------------+ | | | | Arena info block | | Arena 0 +---+ | 4K | | 512G | +------------------+ | | | | +---------------+ | | | | | | | Arena 1 | | Data Blocks | | 512G | | | | | | | +---------------+ | | | . | | | | . | | | | . | | | | | | | | | | | +---------------+ +------------------+ | | | BTT Map | | | | | +------------------+ | | | BTT Flog | | | +------------------+ | Info block copy | | 4K | +------------------+h]hX= Backing Store +-------> Arena +---------------+ | +------------------+ | | | | Arena info block | | Arena 0 +---+ | 4K | | 512G | +------------------+ | | | | +---------------+ | | | | | | | Arena 1 | | Data Blocks | | 512G | | | | | | | +---------------+ | | | . | | | | . | | | | . | | | | | | | | | | | +---------------+ +------------------+ | | | BTT Map | | | | | +------------------+ | | | BTT Flog | | | +------------------+ | Info block copy | | 4K | +------------------+}hjsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1jhhhK(hhhhubeh}(h] static-layoutah ]h"]2. static layoutah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h3. Theory of Operationh]h3. Theory of Operation}(hj8hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj5hhhhhKIubh)}(hhh](h)}(ha. The BTT Maph]ha. The BTT Map}(hjIhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjFhhhhhKMubh)}(hThe map is a simple lookup/indirection table that maps an LBA to an internal block. Each map entry is 32 bits. The two most significant bits are special flags, and the remaining form the internal block number.h]hThe map is a simple lookup/indirection table that maps an LBA to an internal block. Each map entry is 32 bits. The two most significant bits are special flags, and the remaining form the internal block number.}(hjWhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKOhjFhhubhtable)}(hhh]htgroup)}(hhh](hcolspec)}(hhh]h}(h]h ]h"]h$]h&]colwidthKuh1johjlubjp)}(hhh]h}(h]h ]h"]h$]h&]colwidthK=uh1johjlubhthead)}(hhh]hrow)}(hhh](hentry)}(hhh]h)}(hBith]hBit}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKThjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(h Descriptionh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKThjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhjlubhtbody)}(hhh](j)}(hhh](j)}(hhh]h)}(h31 - 30h]h31 - 30}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKVhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](h)}(h2Error and Zero flags - Used in the following way::h]h1Error and Zero flags - Used in the following way:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKVhjubj)}(hX== == ==================================================== 31 30 Description == == ==================================================== 0 0 Initial state. Reads return zeroes; Premap = Postmap 0 1 Zero state: Reads return zeroes 1 0 Error state: Reads fail; Writes clear 'E' bit 1 1 Normal Block – has valid postmap == == ====================================================h]hX== == ==================================================== 31 30 Description == == ==================================================== 0 0 Initial state. Reads return zeroes; Premap = Postmap 0 1 Zero state: Reads return zeroes 1 0 Error state: Reads fail; Writes clear 'E' bit 1 1 Normal Block – has valid postmap == == ====================================================}hjsbah}(h]h ]h"]h$]h&]j+j,uh1jhhhKXhjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(h29 - 0h]h29 - 0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKahjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(h%Mappings to internal 'postmap' blocksh]h)Mappings to internal ‘postmap’ blocks}(hj2hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKahj/ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjlubeh}(h]h ]h"]h$]h&]colsKuh1jjhjgubah}(h]h ]h"]h$]h&]uh1jehjFhhhhhNubh)}(h7Some of the terminology that will be subsequently used:h]h7Some of the terminology that will be subsequently used:}(hj_hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKehjFhhubjf)}(hhh]jk)}(hhh](jp)}(hhh]h}(h]h ]h"]h$]h&]colwidthK uh1johjpubjp)}(hhh]h}(h]h ]h"]h$]h&]colwidthK@uh1johjpubj)}(hhh](j)}(hhh](j)}(hhh]h)}(h External LBAh]h External LBA}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(h$LBA as made visible to upper layers.h]h$LBA as made visible to upper layers.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hABAh]hABA}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKihjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(h9Arena Block Address - Block offset/number within an arenah]h9Arena Block Address - Block offset/number within an arena}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKihjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(h Premap ABAh]h Premap ABA}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKjhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(hYThe block offset into an arena, which was decided upon by range checking the External LBAh]hYThe block offset into an arena, which was decided upon by range checking the External LBA}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKjhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(h Postmap ABAh]h Postmap ABA}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKlhj2ubah}(h]h ]h"]h$]h&]uh1jhj/ubj)}(hhh]h)}(hRThe block number in the "Data Blocks" area obtained after indirection from the maph]hVThe block number in the “Data Blocks” area obtained after indirection from the map}(hjLhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKlhjIubah}(h]h ]h"]h$]h&]uh1jhj/ubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hnfreeh]hnfree}(hjlhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKnhjiubah}(h]h ]h"]h$]h&]uh1jhjfubj)}(hhh]h)}(hThe number of free blocks that are maintained at any given time. This is the number of concurrent writes that can happen to the arena.h]hThe number of free blocks that are maintained at any given time. This is the number of concurrent writes that can happen to the arena.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKnhjubah}(h]h ]h"]h$]h&]uh1jhjfubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjpubeh}(h]h ]h"]h$]h&]colsKuh1jjhjmubah}(h]h ]h"]h$]h&]uh1jehjFhhhhhNubh)}(hX~For example, after adding a BTT, we surface a disk of 1024G. We get a read for the external LBA at 768G. This falls into the second arena, and of the 512G worth of blocks that this arena contributes, this block is at 256G. Thus, the premap ABA is 256G. We now refer to the map, and find out the mapping for block 'X' (256G) points to block 'Y', say '64'. Thus the postmap ABA is 64.h]hXFor example, after adding a BTT, we surface a disk of 1024G. We get a read for the external LBA at 768G. This falls into the second arena, and of the 512G worth of blocks that this arena contributes, this block is at 256G. Thus, the premap ABA is 256G. We now refer to the map, and find out the mapping for block ‘X’ (256G) points to block ‘Y’, say ‘64’. Thus the postmap ABA is 64.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKthjFhhubeh}(h] a-the-btt-mapah ]h"]a. the btt mapah$]h&]uh1hhj5hhhhhKMubh)}(hhh](h)}(hb. The BTT Flogh]hb. The BTT Flog}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhK|ubh)}(hX6The BTT provides sector atomicity by making every write an "allocating write", i.e. Every write goes to a "free" block. A running list of free blocks is maintained in the form of the BTT flog. 'Flog' is a combination of the words "free list" and "log". The flog contains 'nfree' entries, and an entry contains:h]hXNThe BTT provides sector atomicity by making every write an “allocating write”, i.e. Every write goes to a “free” block. A running list of free blocks is maintained in the form of the BTT flog. ‘Flog’ is a combination of the words “free list” and “log”. The flog contains ‘nfree’ entries, and an entry contains:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK~hjhhubjf)}(hhh]jk)}(hhh](jp)}(hhh]h}(h]h ]h"]h$]h&]colwidthKuh1johjubjp)}(hhh]h}(h]h ]h"]h$]h&]colwidthKEuh1johjubj)}(hhh](j)}(hhh](j)}(hhh]h)}(hlbah]hlba}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(h'The premap ABA that is being written toh]h'The premap ABA that is being written to}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hold_maph]hold_map}(hj?hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj<ubah}(h]h ]h"]h$]h&]uh1jhj9ubj)}(hhh]h)}(hNThe old postmap ABA - after 'this' write completes, this will be a free block.h]hRThe old postmap ABA - after ‘this’ write completes, this will be a free block.}(hjVhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjSubah}(h]h ]h"]h$]h&]uh1jhj9ubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hnew_maph]hnew_map}(hjvhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjsubah}(h]h ]h"]h$]h&]uh1jhjpubj)}(hhh]h)}(hThe new postmap ABA. The map will up updated to reflect this lba->postmap_aba mapping, but we log it here in case we have to recover.h]hThe new postmap ABA. The map will up updated to reflect this lba->postmap_aba mapping, but we log it here in case we have to recover.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjpubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hseqh]hseq}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(hSequence number to mark which of the 2 sections of this flog entry is valid/newest. It cycles between 01->10->11->01 (binary) under normal operation, with 00 indicating an uninitialized state.h]hSequence number to mark which of the 2 sections of this flog entry is valid/newest. It cycles between 01->10->11->01 (binary) under normal operation, with 00 indicating an uninitialized state.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hlba'h]hlba’}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(halternate lba entryh]halternate lba entry}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hold_map'h]h old_map’}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(halternate old postmap entryh]halternate old postmap entry}(hj2hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj/ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hnew_map'h]h new_map’}(hjRhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjOubah}(h]h ]h"]h$]h&]uh1jhjLubj)}(hhh]h)}(halternate new postmap entryh]halternate new postmap entry}(hjihhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjfubah}(h]h ]h"]h$]h&]uh1jhjLubeh}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh](j)}(hhh]h)}(hseq'h]hseq’}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hhh]h)}(halternate sequence number.h]halternate sequence number.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]colsKuh1jjhjubah}(h]h ]h"]h$]h&]uh1jehjhhhhhNubh)}(hX^Each of the above fields is 32-bit, making one entry 32 bytes. Entries are also padded to 64 bytes to avoid cache line sharing or aliasing. Flog updates are done such that for any entry being written, it: a. overwrites the 'old' section in the entry based on sequence numbers b. writes the 'new' section such that the sequence number is written last.h]hXfEach of the above fields is 32-bit, making one entry 32 bytes. Entries are also padded to 64 bytes to avoid cache line sharing or aliasing. Flog updates are done such that for any entry being written, it: a. overwrites the ‘old’ section in the entry based on sequence numbers b. writes the ‘new’ section such that the sequence number is written last.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]b-the-btt-flogah ]h"]b. the btt flogah$]h&]uh1hhj5hhhhhK|ubh)}(hhh](h)}(hc. The concept of lanesh]hc. The concept of lanes}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hWhile 'nfree' describes the number of concurrent IOs an arena can process concurrently, 'nlanes' is the number of IOs the BTT device as a whole can process::h]hWhile ‘nfree’ describes the number of concurrent IOs an arena can process concurrently, ‘nlanes’ is the number of IOs the BTT device as a whole can process:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hnlanes = min(nfree, num_cpus)h]hnlanes = min(nfree, num_cpus)}hjsbah}(h]h ]h"]h$]h&]j+j,uh1jhhhKhjhhubh)}(hA lane number is obtained at the start of any IO, and is used for indexing into all the on-disk and in-memory data structures for the duration of the IO. If there are more CPUs than the max number of available lanes, than lanes are protected by spinlocks.h]hA lane number is obtained at the start of any IO, and is used for indexing into all the on-disk and in-memory data structures for the duration of the IO. If there are more CPUs than the max number of available lanes, than lanes are protected by spinlocks.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]c-the-concept-of-lanesah ]h"]c. the concept of lanesah$]h&]uh1hhj5hhhhhKubh)}(hhh](h)}(h6d. In-memory data structure: Read Tracking Table (RTT)h]h6d. In-memory data structure: Read Tracking Table (RTT)}(hj)hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj&hhhhhKubh)}(hXConsider a case where we have two threads, one doing reads and the other, writes. We can hit a condition where the writer thread grabs a free block to do a new IO, but the (slow) reader thread is still reading from it. In other words, the reader consulted a map entry, and started reading the corresponding block. A writer started writing to the same external LBA, and finished the write updating the map for that external LBA to point to its new postmap ABA. At this point the internal, postmap block that the reader is (still) reading has been inserted into the list of free blocks. If another write comes in for the same LBA, it can grab this free block, and start writing to it, causing the reader to read incorrect data. To prevent this, we introduce the RTT.h]hXConsider a case where we have two threads, one doing reads and the other, writes. We can hit a condition where the writer thread grabs a free block to do a new IO, but the (slow) reader thread is still reading from it. In other words, the reader consulted a map entry, and started reading the corresponding block. A writer started writing to the same external LBA, and finished the write updating the map for that external LBA to point to its new postmap ABA. At this point the internal, postmap block that the reader is (still) reading has been inserted into the list of free blocks. If another write comes in for the same LBA, it can grab this free block, and start writing to it, causing the reader to read incorrect data. To prevent this, we introduce the RTT.}(hj7hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj&hhubh)}(hX~The RTT is a simple, per arena table with 'nfree' entries. Every reader inserts into rtt[lane_number], the postmap ABA it is reading, and clears it after the read is complete. Every writer thread, after grabbing a free block, checks the RTT for its presence. If the postmap free block is in the RTT, it waits till the reader clears the RTT entry, and only then starts writing to it.h]hXThe RTT is a simple, per arena table with ‘nfree’ entries. Every reader inserts into rtt[lane_number], the postmap ABA it is reading, and clears it after the read is complete. Every writer thread, after grabbing a free block, checks the RTT for its presence. If the postmap free block is in the RTT, it waits till the reader clears the RTT entry, and only then starts writing to it.}(hjEhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj&hhubeh}(h]2d-in-memory-data-structure-read-tracking-table-rttah ]h"]6d. in-memory data structure: read tracking table (rtt)ah$]h&]uh1hhj5hhhhhKubh)}(hhh](h)}(h&e. In-memory data structure: map locksh]h&e. In-memory data structure: map locks}(hj^hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj[hhhhhKubh)}(h~Consider a case where two writer threads are writing to the same LBA. There can be a race in the following sequence of steps::h]h}Consider a case where two writer threads are writing to the same LBA. There can be a race in the following sequence of steps:}(hjlhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj[hhubj)}(h:free[lane] = map[premap_aba] map[premap_aba] = postmap_abah]h:free[lane] = map[premap_aba] map[premap_aba] = postmap_aba}hjzsbah}(h]h ]h"]h$]h&]j+j,uh1jhhhKhj[hhubh)}(hBoth threads can update their respective free[lane] with the same old, freed postmap_aba. This has made the layout inconsistent by losing a free entry, and at the same time, duplicating another free entry for two lanes.h]hBoth threads can update their respective free[lane] with the same old, freed postmap_aba. This has made the layout inconsistent by losing a free entry, and at the same time, duplicating another free entry for two lanes.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj[hhubh)}(hTo solve this, we could have a single map lock (per arena) that has to be taken before performing the above sequence, but we feel that could be too contentious. Instead we use an array of (nfree) map_locks that is indexed by (premap_aba modulo nfree).h]hTo solve this, we could have a single map lock (per arena) that has to be taken before performing the above sequence, but we feel that could be too contentious. Instead we use an array of (nfree) map_locks that is indexed by (premap_aba modulo nfree).}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj[hhubeh}(h]$e-in-memory-data-structure-map-locksah ]h"]&e. in-memory data structure: map locksah$]h&]uh1hhj5hhhhhKubh)}(hhh](h)}(hf. Reconstruction from the Flogh]hf. Reconstruction from the Flog}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hXOn startup, we analyze the BTT flog to create our list of free blocks. We walk through all the entries, and for each lane, of the set of two possible 'sections', we always look at the most recent one only (based on the sequence number). The reconstruction rules/steps are simple:h]hXOn startup, we analyze the BTT flog to create our list of free blocks. We walk through all the entries, and for each lane, of the set of two possible ‘sections’, we always look at the most recent one only (based on the sequence number). The reconstruction rules/steps are simple:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh bullet_list)}(hhh](h list_item)}(hRead map[log_entry.lba].h]h)}(hjh]hRead map[log_entry.lba].}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hCIf log_entry.new matches the map entry, then log_entry.old is free.h]h)}(hjh]hCIf log_entry.new matches the map entry, then log_entry.old is free.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hIf log_entry.new does not match the map entry, then log_entry.new is free. (This case can only be caused by power-fails/unsafe shutdowns) h]h)}(hIf log_entry.new does not match the map entry, then log_entry.new is free. (This case can only be caused by power-fails/unsafe shutdowns)h]hIf log_entry.new does not match the map entry, then log_entry.new is free. (This case can only be caused by power-fails/unsafe shutdowns)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]h ]h"]h$]h&]bullet-uh1jhhhKhjhhubeh}(h]f-reconstruction-from-the-flogah ]h"]f. reconstruction from the flogah$]h&]uh1hhj5hhhhhKubh)}(hhh](h)}(h%g. Summarizing - Read and Write flowsh]h%g. Summarizing - Read and Write flows}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj(hhhhhKubh)}(hRead:h]hRead:}(hj9hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj(hhubhenumerated_list)}(hhh](j)}(h2Convert external LBA to arena number + pre-map ABAh]h)}(hjNh]h2Convert external LBA to arena number + pre-map ABA}(hjPhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjLubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(hGet a lane (and take lane_lock)h]h)}(hjeh]hGet a lane (and take lane_lock)}(hjghhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjcubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(h.Read map to get the entry for this pre-map ABAh]h)}(hj|h]h.Read map to get the entry for this pre-map ABA}(hj~hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjzubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(h!Enter post-map ABA into RTT[lane]h]h)}(hjh]h!Enter post-map ABA into RTT[lane]}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(hAIf TRIM flag set in map, return zeroes, and end IO (go to step 8)h]h)}(hjh]hAIf TRIM flag set in map, return zeroes, and end IO (go to step 8)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(h8If ERROR flag set in map, end IO with EIO (go to step 8)h]h)}(hjh]h8If ERROR flag set in map, end IO with EIO (go to step 8)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(hRead data from this blockh]h)}(hjh]hRead data from this block}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(h(Remove post-map ABA entry from RTT[lane]h]h)}(hjh]h(Remove post-map ABA entry from RTT[lane]}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubj)}(hRelease lane (and lane_lock) h]h)}(hRelease lane (and lane_lock)h]hRelease lane (and lane_lock)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjIhhhhhNubeh}(h]h ]h"]h$]h&]enumtypearabicprefixhsuffix.uh1jGhj(hhhhhKubh)}(hWrite:h]hWrite:}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj(hhubjH)}(hhh](j)}(h2Convert external LBA to Arena number + pre-map ABAh]h)}(hj:h]h2Convert external LBA to Arena number + pre-map ABA}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj8ubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hGet a lane (and take lane_lock)h]h)}(hjQh]hGet a lane (and take lane_lock)}(hjShhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjOubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hhUse lane to index into in-memory free list and obtain a new block, next flog index, next sequence numberh]h)}(hhUse lane to index into in-memory free list and obtain a new block, next flog index, next sequence numberh]hhUse lane to index into in-memory free list and obtain a new block, next flog index, next sequence number}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjfubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hGScan the RTT to check if free block is present, and spin/wait if it is.h]h)}(hjh]hGScan the RTT to check if free block is present, and spin/wait if it is.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj~ubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hWrite data to this free blockh]h)}(hjh]hWrite data to this free block}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hDRead map to get the existing post-map ABA entry for this pre-map ABAh]h)}(hjh]hDRead map to get the existing post-map ABA entry for this pre-map ABA}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hLWrite flog entry: [premap_aba / old postmap_aba / new postmap_aba / seq_num]h]h)}(hjh]hLWrite flog entry: [premap_aba / old postmap_aba / new postmap_aba / seq_num]}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(h Write new post-map ABA into map.h]h)}(hjh]h Write new post-map ABA into map.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(h+Write old post-map entry into the free listh]h)}(hjh]h+Write old post-map entry into the free list}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hACalculate next sequence number and write into the free list entryh]h)}(hj h]hACalculate next sequence number and write into the free list entry}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubj)}(hRelease lane (and lane_lock) h]h)}(hRelease lane (and lane_lock)h]hRelease lane (and lane_lock)}(hj# hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj5hhhhhNubeh}(h]h ]h"]h$]h&]j"j#j$hj%j&uh1jGhj(hhhhhKubeh}(h]"g-summarizing-read-and-write-flowsah ]h"]%g. summarizing - read and write flowsah$]h&]uh1hhj5hhhhhKubeh}(h]theory-of-operationah ]h"]3. theory of operationah$]h&]uh1hhhhhhhhKIubh)}(hhh](h)}(h4. Error Handlingh]h4. Error Handling}(hjP hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjM hhhhhKubh)}(hAn arena would be in an error state if any of the metadata is corrupted irrecoverably, either due to a bug or a media error. The following conditions indicate an error:h]hAn arena would be in an error state if any of the metadata is corrupted irrecoverably, either due to a bug or a media error. The following conditions indicate an error:}(hj^ hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjM hhubj)}(hhh](j)}(hLInfo block checksum does not match (and recovering from the copy also fails)h]h)}(hjq h]hLInfo block checksum does not match (and recovering from the copy also fails)}(hjs hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjo ubah}(h]h ]h"]h$]h&]uh1jhjl hhhhhNubj)}(hAll internal available blocks are not uniquely and entirely addressed by the sum of mapped blocks and free blocks (from the BTT flog).h]h)}(hAll internal available blocks are not uniquely and entirely addressed by the sum of mapped blocks and free blocks (from the BTT flog).h]hAll internal available blocks are not uniquely and entirely addressed by the sum of mapped blocks and free blocks (from the BTT flog).}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1jhjl hhhhhNubj)}(hORebuilding free list from the flog reveals missing/duplicate/impossible entriesh]h)}(hORebuilding free list from the flog reveals missing/duplicate/impossible entriesh]hORebuilding free list from the flog reveals missing/duplicate/impossible entries}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1jhjl hhhhhNubj)}(hA map entry is out of bounds h]h)}(hA map entry is out of boundsh]hA map entry is out of bounds}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM hj ubah}(h]h ]h"]h$]h&]uh1jhjl hhhhhNubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjM hhubh)}(hyIf any of these error conditions are encountered, the arena is put into a read only state using a flag in the info block.h]hyIf any of these error conditions are encountered, the arena is put into a read only state using a flag in the info block.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM hjM hhubeh}(h]error-handlingah ]h"]4. error handlingah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(h5. Usageh]h5. Usage}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hhhhhMubh)}(hThe BTT can be set up on any disk (namespace) exposed by the libnvdimm subsystem (pmem, or blk mode). The easiest way to set up such a namespace is using the 'ndctl' utility [1]:h]hThe BTT can be set up on any disk (namespace) exposed by the libnvdimm subsystem (pmem, or blk mode). The easiest way to set up such a namespace is using the ‘ndctl’ utility [1]:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj hhubh)}(hMFor example, the ndctl command line to setup a btt with a 4k sector size is::h]hLFor example, the ndctl command line to setup a btt with a 4k sector size is:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj hhubj)}(h9ndctl create-namespace -f -e namespace0.0 -m sector -l 4kh]h9ndctl create-namespace -f -e namespace0.0 -m sector -l 4k}hj sbah}(h]h ]h"]h$]h&]j+j,uh1jhhhMhj hhubh)}(h3See ndctl create-namespace --help for more options.h]h3See ndctl create-namespace --help for more options.}(hj% hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj hhubh)}(h"[1]: https://github.com/pmem/ndctlh](h[1]: }(hj3 hhhNhNubh reference)}(hhttps://github.com/pmem/ndctlh]hhttps://github.com/pmem/ndctl}(hj= hhhNhNubah}(h]h ]h"]h$]h&]refurij? uh1j; hj3 ubeh}(h]h ]h"]h$]h&]uh1hhhhMhj hhubeh}(h]usageah ]h"]5. usageah$]h&]uh1hhhhhhhhMubeh}(h]btt-block-translation-tableah ]h"]btt - block translation tableah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksjfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerj error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(j_ j\ hhj2j/jJ jG jjjjj#j jXjUjjj%j"jB j? j j jW jT u nametypes}(j_ hj2jJ jjj#jXjj%jB j jW uh}(j\ hhhj/hjG j5jjFjjj jjUj&jj[j"jj? j(j jM jT j u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}Rparse_messages]transform_messages] transformerN include_log] decorationNhhub.