Back to home page

OSCL-LXR

 
 

    


0001 ===============================
0002 LIBNVDIMM: Non-Volatile Devices
0003 ===============================
0004 
0005 libnvdimm - kernel / libndctl - userspace helper library
0006 
0007 nvdimm@lists.linux.dev
0008 
0009 Version 13
0010 
0011 .. contents:
0012 
0013         Glossary
0014         Overview
0015             Supporting Documents
0016             Git Trees
0017         LIBNVDIMM PMEM
0018             PMEM-REGIONs, Atomic Sectors, and DAX
0019         Example NVDIMM Platform
0020         LIBNVDIMM Kernel Device Model and LIBNDCTL Userspace API
0021             LIBNDCTL: Context
0022                 libndctl: instantiate a new library context example
0023             LIBNVDIMM/LIBNDCTL: Bus
0024                 libnvdimm: control class device in /sys/class
0025                 libnvdimm: bus
0026                 libndctl: bus enumeration example
0027             LIBNVDIMM/LIBNDCTL: DIMM (NMEM)
0028                 libnvdimm: DIMM (NMEM)
0029                 libndctl: DIMM enumeration example
0030             LIBNVDIMM/LIBNDCTL: Region
0031                 libnvdimm: region
0032                 libndctl: region enumeration example
0033                 Why Not Encode the Region Type into the Region Name?
0034                 How Do I Determine the Major Type of a Region?
0035             LIBNVDIMM/LIBNDCTL: Namespace
0036                 libnvdimm: namespace
0037                 libndctl: namespace enumeration example
0038                 libndctl: namespace creation example
0039                 Why the Term "namespace"?
0040             LIBNVDIMM/LIBNDCTL: Block Translation Table "btt"
0041                 libnvdimm: btt layout
0042                 libndctl: btt creation example
0043         Summary LIBNDCTL Diagram
0044 
0045 
0046 Glossary
0047 ========
0048 
0049 PMEM:
0050   A system-physical-address range where writes are persistent.  A
0051   block device composed of PMEM is capable of DAX.  A PMEM address range
0052   may span an interleave of several DIMMs.
0053 
0054 DPA:
0055   DIMM Physical Address, is a DIMM-relative offset.  With one DIMM in
0056   the system there would be a 1:1 system-physical-address:DPA association.
0057   Once more DIMMs are added a memory controller interleave must be
0058   decoded to determine the DPA associated with a given
0059   system-physical-address.
0060 
0061 DAX:
0062   File system extensions to bypass the page cache and block layer to
0063   mmap persistent memory, from a PMEM block device, directly into a
0064   process address space.
0065 
0066 DSM:
0067   Device Specific Method: ACPI method to control specific
0068   device - in this case the firmware.
0069 
0070 DCR:
0071   NVDIMM Control Region Structure defined in ACPI 6 Section 5.2.25.5.
0072   It defines a vendor-id, device-id, and interface format for a given DIMM.
0073 
0074 BTT:
0075   Block Translation Table: Persistent memory is byte addressable.
0076   Existing software may have an expectation that the power-fail-atomicity
0077   of writes is at least one sector, 512 bytes.  The BTT is an indirection
0078   table with atomic update semantics to front a PMEM block device
0079   driver and present arbitrary atomic sector sizes.
0080 
0081 LABEL:
0082   Metadata stored on a DIMM device that partitions and identifies
0083   (persistently names) capacity allocated to different PMEM namespaces. It
0084   also indicates whether an address abstraction like a BTT is applied to
0085   the namepsace.  Note that traditional partition tables, GPT/MBR, are
0086   layered on top of a PMEM namespace, or an address abstraction like BTT
0087   if present, but partition support is deprecated going forward.
0088 
0089 
0090 Overview
0091 ========
0092 
0093 The LIBNVDIMM subsystem provides support for PMEM described by platform
0094 firmware or a device driver. On ACPI based systems the platform firmware
0095 conveys persistent memory resource via the ACPI NFIT "NVDIMM Firmware
0096 Interface Table" in ACPI 6. While the LIBNVDIMM subsystem implementation
0097 is generic and supports pre-NFIT platforms, it was guided by the
0098 superset of capabilities need to support this ACPI 6 definition for
0099 NVDIMM resources. The original implementation supported the
0100 block-window-aperture capability described in the NFIT, but that support
0101 has since been abandoned and never shipped in a product.
0102 
0103 Supporting Documents
0104 --------------------
0105 
0106 ACPI 6:
0107         https://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf
0108 NVDIMM Namespace:
0109         https://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
0110 DSM Interface Example:
0111         https://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
0112 Driver Writer's Guide:
0113         https://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf
0114 
0115 Git Trees
0116 ---------
0117 
0118 LIBNVDIMM:
0119         https://git.kernel.org/cgit/linux/kernel/git/nvdimm/nvdimm.git
0120 LIBNDCTL:
0121         https://github.com/pmem/ndctl.git
0122 
0123 
0124 LIBNVDIMM PMEM
0125 ==============
0126 
0127 Prior to the arrival of the NFIT, non-volatile memory was described to a
0128 system in various ad-hoc ways.  Usually only the bare minimum was
0129 provided, namely, a single system-physical-address range where writes
0130 are expected to be durable after a system power loss.  Now, the NFIT
0131 specification standardizes not only the description of PMEM, but also
0132 platform message-passing entry points for control and configuration.
0133 
0134 PMEM (nd_pmem.ko): Drives a system-physical-address range.  This range is
0135 contiguous in system memory and may be interleaved (hardware memory controller
0136 striped) across multiple DIMMs.  When interleaved the platform may optionally
0137 provide details of which DIMMs are participating in the interleave.
0138 
0139 It is worth noting that when the labeling capability is detected (a EFI
0140 namespace label index block is found), then no block device is created
0141 by default as userspace needs to do at least one allocation of DPA to
0142 the PMEM range.  In contrast ND_NAMESPACE_IO ranges, once registered,
0143 can be immediately attached to nd_pmem. This latter mode is called
0144 label-less or "legacy".
0145 
0146 PMEM-REGIONs, Atomic Sectors, and DAX
0147 -------------------------------------
0148 
0149 For the cases where an application or filesystem still needs atomic sector
0150 update guarantees it can register a BTT on a PMEM device or partition.  See
0151 LIBNVDIMM/NDCTL: Block Translation Table "btt"
0152 
0153 
0154 Example NVDIMM Platform
0155 =======================
0156 
0157 For the remainder of this document the following diagram will be
0158 referenced for any example sysfs layouts::
0159 
0160 
0161                                (a)               (b)           DIMM
0162             +-------------------+--------+--------+--------+
0163   +------+  |       pm0.0       |  free  | pm1.0  |  free  |    0
0164   | imc0 +--+- - - region0- - - +--------+        +--------+
0165   +--+---+  |       pm0.0       |  free  | pm1.0  |  free  |    1
0166      |      +-------------------+--------v        v--------+
0167   +--+---+                               |                 |
0168   | cpu0 |                                     region1
0169   +--+---+                               |                 |
0170      |      +----------------------------^        ^--------+
0171   +--+---+  |           free             | pm1.0  |  free  |    2
0172   | imc1 +--+----------------------------|        +--------+
0173   +------+  |           free             | pm1.0  |  free  |    3
0174             +----------------------------+--------+--------+
0175 
0176 In this platform we have four DIMMs and two memory controllers in one
0177 socket.  Each PMEM interleave set is identified by a region device with
0178 a dynamically assigned id.
0179 
0180     1. The first portion of DIMM0 and DIMM1 are interleaved as REGION0. A
0181        single PMEM namespace is created in the REGION0-SPA-range that spans most
0182        of DIMM0 and DIMM1 with a user-specified name of "pm0.0". Some of that
0183        interleaved system-physical-address range is left free for
0184        another PMEM namespace to be defined.
0185 
0186     2. In the last portion of DIMM0 and DIMM1 we have an interleaved
0187        system-physical-address range, REGION1, that spans those two DIMMs as
0188        well as DIMM2 and DIMM3.  Some of REGION1 is allocated to a PMEM namespace
0189        named "pm1.0".
0190 
0191     This bus is provided by the kernel under the device
0192     /sys/devices/platform/nfit_test.0 when the nfit_test.ko module from
0193     tools/testing/nvdimm is loaded. This module is a unit test for
0194     LIBNVDIMM and the  acpi_nfit.ko driver.
0195 
0196 
0197 LIBNVDIMM Kernel Device Model and LIBNDCTL Userspace API
0198 ========================================================
0199 
0200 What follows is a description of the LIBNVDIMM sysfs layout and a
0201 corresponding object hierarchy diagram as viewed through the LIBNDCTL
0202 API.  The example sysfs paths and diagrams are relative to the Example
0203 NVDIMM Platform which is also the LIBNVDIMM bus used in the LIBNDCTL unit
0204 test.
0205 
0206 LIBNDCTL: Context
0207 -----------------
0208 
0209 Every API call in the LIBNDCTL library requires a context that holds the
0210 logging parameters and other library instance state.  The library is
0211 based on the libabc template:
0212 
0213         https://git.kernel.org/cgit/linux/kernel/git/kay/libabc.git
0214 
0215 LIBNDCTL: instantiate a new library context example
0216 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0217 
0218 ::
0219 
0220         struct ndctl_ctx *ctx;
0221 
0222         if (ndctl_new(&ctx) == 0)
0223                 return ctx;
0224         else
0225                 return NULL;
0226 
0227 LIBNVDIMM/LIBNDCTL: Bus
0228 -----------------------
0229 
0230 A bus has a 1:1 relationship with an NFIT.  The current expectation for
0231 ACPI based systems is that there is only ever one platform-global NFIT.
0232 That said, it is trivial to register multiple NFITs, the specification
0233 does not preclude it.  The infrastructure supports multiple busses and
0234 we use this capability to test multiple NFIT configurations in the unit
0235 test.
0236 
0237 LIBNVDIMM: control class device in /sys/class
0238 ---------------------------------------------
0239 
0240 This character device accepts DSM messages to be passed to DIMM
0241 identified by its NFIT handle::
0242 
0243         /sys/class/nd/ndctl0
0244         |-- dev
0245         |-- device -> ../../../ndbus0
0246         |-- subsystem -> ../../../../../../../class/nd
0247 
0248 
0249 
0250 LIBNVDIMM: bus
0251 --------------
0252 
0253 ::
0254 
0255         struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
0256                struct nvdimm_bus_descriptor *nfit_desc);
0257 
0258 ::
0259 
0260         /sys/devices/platform/nfit_test.0/ndbus0
0261         |-- commands
0262         |-- nd
0263         |-- nfit
0264         |-- nmem0
0265         |-- nmem1
0266         |-- nmem2
0267         |-- nmem3
0268         |-- power
0269         |-- provider
0270         |-- region0
0271         |-- region1
0272         |-- region2
0273         |-- region3
0274         |-- region4
0275         |-- region5
0276         |-- uevent
0277         `-- wait_probe
0278 
0279 LIBNDCTL: bus enumeration example
0280 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0281 
0282 Find the bus handle that describes the bus from Example NVDIMM Platform::
0283 
0284         static struct ndctl_bus *get_bus_by_provider(struct ndctl_ctx *ctx,
0285                         const char *provider)
0286         {
0287                 struct ndctl_bus *bus;
0288 
0289                 ndctl_bus_foreach(ctx, bus)
0290                         if (strcmp(provider, ndctl_bus_get_provider(bus)) == 0)
0291                                 return bus;
0292 
0293                 return NULL;
0294         }
0295 
0296         bus = get_bus_by_provider(ctx, "nfit_test.0");
0297 
0298 
0299 LIBNVDIMM/LIBNDCTL: DIMM (NMEM)
0300 -------------------------------
0301 
0302 The DIMM device provides a character device for sending commands to
0303 hardware, and it is a container for LABELs.  If the DIMM is defined by
0304 NFIT then an optional 'nfit' attribute sub-directory is available to add
0305 NFIT-specifics.
0306 
0307 Note that the kernel device name for "DIMMs" is "nmemX".  The NFIT
0308 describes these devices via "Memory Device to System Physical Address
0309 Range Mapping Structure", and there is no requirement that they actually
0310 be physical DIMMs, so we use a more generic name.
0311 
0312 LIBNVDIMM: DIMM (NMEM)
0313 ^^^^^^^^^^^^^^^^^^^^^^
0314 
0315 ::
0316 
0317         struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
0318                         const struct attribute_group **groups, unsigned long flags,
0319                         unsigned long *dsm_mask);
0320 
0321 ::
0322 
0323         /sys/devices/platform/nfit_test.0/ndbus0
0324         |-- nmem0
0325         |   |-- available_slots
0326         |   |-- commands
0327         |   |-- dev
0328         |   |-- devtype
0329         |   |-- driver -> ../../../../../bus/nd/drivers/nvdimm
0330         |   |-- modalias
0331         |   |-- nfit
0332         |   |   |-- device
0333         |   |   |-- format
0334         |   |   |-- handle
0335         |   |   |-- phys_id
0336         |   |   |-- rev_id
0337         |   |   |-- serial
0338         |   |   `-- vendor
0339         |   |-- state
0340         |   |-- subsystem -> ../../../../../bus/nd
0341         |   `-- uevent
0342         |-- nmem1
0343         [..]
0344 
0345 
0346 LIBNDCTL: DIMM enumeration example
0347 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0348 
0349 Note, in this example we are assuming NFIT-defined DIMMs which are
0350 identified by an "nfit_handle" a 32-bit value where:
0351 
0352    - Bit 3:0 DIMM number within the memory channel
0353    - Bit 7:4 memory channel number
0354    - Bit 11:8 memory controller ID
0355    - Bit 15:12 socket ID (within scope of a Node controller if node
0356      controller is present)
0357    - Bit 27:16 Node Controller ID
0358    - Bit 31:28 Reserved
0359 
0360 ::
0361 
0362         static struct ndctl_dimm *get_dimm_by_handle(struct ndctl_bus *bus,
0363                unsigned int handle)
0364         {
0365                 struct ndctl_dimm *dimm;
0366 
0367                 ndctl_dimm_foreach(bus, dimm)
0368                         if (ndctl_dimm_get_handle(dimm) == handle)
0369                                 return dimm;
0370 
0371                 return NULL;
0372         }
0373 
0374         #define DIMM_HANDLE(n, s, i, c, d) \
0375                 (((n & 0xfff) << 16) | ((s & 0xf) << 12) | ((i & 0xf) << 8) \
0376                  | ((c & 0xf) << 4) | (d & 0xf))
0377 
0378         dimm = get_dimm_by_handle(bus, DIMM_HANDLE(0, 0, 0, 0, 0));
0379 
0380 LIBNVDIMM/LIBNDCTL: Region
0381 --------------------------
0382 
0383 A generic REGION device is registered for each PMEM interleave-set /
0384 range. Per the example there are 2 PMEM regions on the "nfit_test.0"
0385 bus. The primary role of regions are to be a container of "mappings".  A
0386 mapping is a tuple of <DIMM, DPA-start-offset, length>.
0387 
0388 LIBNVDIMM provides a built-in driver for REGION devices.  This driver
0389 is responsible for all parsing LABELs, if present, and then emitting NAMESPACE
0390 devices for the nd_pmem driver to consume.
0391 
0392 In addition to the generic attributes of "mapping"s, "interleave_ways"
0393 and "size" the REGION device also exports some convenience attributes.
0394 "nstype" indicates the integer type of namespace-device this region
0395 emits, "devtype" duplicates the DEVTYPE variable stored by udev at the
0396 'add' event, "modalias" duplicates the MODALIAS variable stored by udev
0397 at the 'add' event, and finally, the optional "spa_index" is provided in
0398 the case where the region is defined by a SPA.
0399 
0400 LIBNVDIMM: region::
0401 
0402         struct nd_region *nvdimm_pmem_region_create(struct nvdimm_bus *nvdimm_bus,
0403                         struct nd_region_desc *ndr_desc);
0404 
0405 ::
0406 
0407         /sys/devices/platform/nfit_test.0/ndbus0
0408         |-- region0
0409         |   |-- available_size
0410         |   |-- btt0
0411         |   |-- btt_seed
0412         |   |-- devtype
0413         |   |-- driver -> ../../../../../bus/nd/drivers/nd_region
0414         |   |-- init_namespaces
0415         |   |-- mapping0
0416         |   |-- mapping1
0417         |   |-- mappings
0418         |   |-- modalias
0419         |   |-- namespace0.0
0420         |   |-- namespace_seed
0421         |   |-- numa_node
0422         |   |-- nfit
0423         |   |   `-- spa_index
0424         |   |-- nstype
0425         |   |-- set_cookie
0426         |   |-- size
0427         |   |-- subsystem -> ../../../../../bus/nd
0428         |   `-- uevent
0429         |-- region1
0430         [..]
0431 
0432 LIBNDCTL: region enumeration example
0433 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0434 
0435 Sample region retrieval routines based on NFIT-unique data like
0436 "spa_index" (interleave set id).
0437 
0438 ::
0439 
0440         static struct ndctl_region *get_pmem_region_by_spa_index(struct ndctl_bus *bus,
0441                         unsigned int spa_index)
0442         {
0443                 struct ndctl_region *region;
0444 
0445                 ndctl_region_foreach(bus, region) {
0446                         if (ndctl_region_get_type(region) != ND_DEVICE_REGION_PMEM)
0447                                 continue;
0448                         if (ndctl_region_get_spa_index(region) == spa_index)
0449                                 return region;
0450                 }
0451                 return NULL;
0452         }
0453 
0454 
0455 LIBNVDIMM/LIBNDCTL: Namespace
0456 -----------------------------
0457 
0458 A REGION, after resolving DPA aliasing and LABEL specified boundaries, surfaces
0459 one or more "namespace" devices.  The arrival of a "namespace" device currently
0460 triggers the nd_pmem driver to load and register a disk/block device.
0461 
0462 LIBNVDIMM: namespace
0463 ^^^^^^^^^^^^^^^^^^^^
0464 
0465 Here is a sample layout from the 2 major types of NAMESPACE where namespace0.0
0466 represents DIMM-info-backed PMEM (note that it has a 'uuid' attribute), and
0467 namespace1.0 represents an anonymous PMEM namespace (note that has no 'uuid'
0468 attribute due to not support a LABEL)
0469 
0470 ::
0471 
0472         /sys/devices/platform/nfit_test.0/ndbus0/region0/namespace0.0
0473         |-- alt_name
0474         |-- devtype
0475         |-- dpa_extents
0476         |-- force_raw
0477         |-- modalias
0478         |-- numa_node
0479         |-- resource
0480         |-- size
0481         |-- subsystem -> ../../../../../../bus/nd
0482         |-- type
0483         |-- uevent
0484         `-- uuid
0485         /sys/devices/platform/nfit_test.1/ndbus1/region1/namespace1.0
0486         |-- block
0487         |   `-- pmem0
0488         |-- devtype
0489         |-- driver -> ../../../../../../bus/nd/drivers/pmem
0490         |-- force_raw
0491         |-- modalias
0492         |-- numa_node
0493         |-- resource
0494         |-- size
0495         |-- subsystem -> ../../../../../../bus/nd
0496         |-- type
0497         `-- uevent
0498 
0499 LIBNDCTL: namespace enumeration example
0500 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0501 Namespaces are indexed relative to their parent region, example below.
0502 These indexes are mostly static from boot to boot, but subsystem makes
0503 no guarantees in this regard.  For a static namespace identifier use its
0504 'uuid' attribute.
0505 
0506 ::
0507 
0508   static struct ndctl_namespace
0509   *get_namespace_by_id(struct ndctl_region *region, unsigned int id)
0510   {
0511           struct ndctl_namespace *ndns;
0512 
0513           ndctl_namespace_foreach(region, ndns)
0514                   if (ndctl_namespace_get_id(ndns) == id)
0515                           return ndns;
0516 
0517           return NULL;
0518   }
0519 
0520 LIBNDCTL: namespace creation example
0521 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0522 
0523 Idle namespaces are automatically created by the kernel if a given
0524 region has enough available capacity to create a new namespace.
0525 Namespace instantiation involves finding an idle namespace and
0526 configuring it.  For the most part the setting of namespace attributes
0527 can occur in any order, the only constraint is that 'uuid' must be set
0528 before 'size'.  This enables the kernel to track DPA allocations
0529 internally with a static identifier::
0530 
0531   static int configure_namespace(struct ndctl_region *region,
0532                   struct ndctl_namespace *ndns,
0533                   struct namespace_parameters *parameters)
0534   {
0535           char devname[50];
0536 
0537           snprintf(devname, sizeof(devname), "namespace%d.%d",
0538                           ndctl_region_get_id(region), paramaters->id);
0539 
0540           ndctl_namespace_set_alt_name(ndns, devname);
0541           /* 'uuid' must be set prior to setting size! */
0542           ndctl_namespace_set_uuid(ndns, paramaters->uuid);
0543           ndctl_namespace_set_size(ndns, paramaters->size);
0544           /* unlike pmem namespaces, blk namespaces have a sector size */
0545           if (parameters->lbasize)
0546                   ndctl_namespace_set_sector_size(ndns, parameters->lbasize);
0547           ndctl_namespace_enable(ndns);
0548   }
0549 
0550 
0551 Why the Term "namespace"?
0552 ^^^^^^^^^^^^^^^^^^^^^^^^^
0553 
0554     1. Why not "volume" for instance?  "volume" ran the risk of confusing
0555        ND (libnvdimm subsystem) to a volume manager like device-mapper.
0556 
0557     2. The term originated to describe the sub-devices that can be created
0558        within a NVME controller (see the nvme specification:
0559        https://www.nvmexpress.org/specifications/), and NFIT namespaces are
0560        meant to parallel the capabilities and configurability of
0561        NVME-namespaces.
0562 
0563 
0564 LIBNVDIMM/LIBNDCTL: Block Translation Table "btt"
0565 -------------------------------------------------
0566 
0567 A BTT (design document: https://pmem.io/2014/09/23/btt.html) is a
0568 personality driver for a namespace that fronts entire namespace as an
0569 'address abstraction'.
0570 
0571 LIBNVDIMM: btt layout
0572 ^^^^^^^^^^^^^^^^^^^^^
0573 
0574 Every region will start out with at least one BTT device which is the
0575 seed device.  To activate it set the "namespace", "uuid", and
0576 "sector_size" attributes and then bind the device to the nd_pmem or
0577 nd_blk driver depending on the region type::
0578 
0579         /sys/devices/platform/nfit_test.1/ndbus0/region0/btt0/
0580         |-- namespace
0581         |-- delete
0582         |-- devtype
0583         |-- modalias
0584         |-- numa_node
0585         |-- sector_size
0586         |-- subsystem -> ../../../../../bus/nd
0587         |-- uevent
0588         `-- uuid
0589 
0590 LIBNDCTL: btt creation example
0591 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0592 
0593 Similar to namespaces an idle BTT device is automatically created per
0594 region.  Each time this "seed" btt device is configured and enabled a new
0595 seed is created.  Creating a BTT configuration involves two steps of
0596 finding and idle BTT and assigning it to consume a namespace.
0597 
0598 ::
0599 
0600         static struct ndctl_btt *get_idle_btt(struct ndctl_region *region)
0601         {
0602                 struct ndctl_btt *btt;
0603 
0604                 ndctl_btt_foreach(region, btt)
0605                         if (!ndctl_btt_is_enabled(btt)
0606                                         && !ndctl_btt_is_configured(btt))
0607                                 return btt;
0608 
0609                 return NULL;
0610         }
0611 
0612         static int configure_btt(struct ndctl_region *region,
0613                         struct btt_parameters *parameters)
0614         {
0615                 btt = get_idle_btt(region);
0616 
0617                 ndctl_btt_set_uuid(btt, parameters->uuid);
0618                 ndctl_btt_set_sector_size(btt, parameters->sector_size);
0619                 ndctl_btt_set_namespace(btt, parameters->ndns);
0620                 /* turn off raw mode device */
0621                 ndctl_namespace_disable(parameters->ndns);
0622                 /* turn on btt access */
0623                 ndctl_btt_enable(btt);
0624         }
0625 
0626 Once instantiated a new inactive btt seed device will appear underneath
0627 the region.
0628 
0629 Once a "namespace" is removed from a BTT that instance of the BTT device
0630 will be deleted or otherwise reset to default values.  This deletion is
0631 only at the device model level.  In order to destroy a BTT the "info
0632 block" needs to be destroyed.  Note, that to destroy a BTT the media
0633 needs to be written in raw mode.  By default, the kernel will autodetect
0634 the presence of a BTT and disable raw mode.  This autodetect behavior
0635 can be suppressed by enabling raw mode for the namespace via the
0636 ndctl_namespace_set_raw_mode() API.
0637 
0638 
0639 Summary LIBNDCTL Diagram
0640 ------------------------
0641 
0642 For the given example above, here is the view of the objects as seen by the
0643 LIBNDCTL API::
0644 
0645               +---+
0646               |CTX|
0647               +-+-+
0648                 |
0649   +-------+     |
0650   | DIMM0 <-+   |      +---------+   +--------------+  +---------------+
0651   +-------+ |   |    +-> REGION0 +---> NAMESPACE0.0 +--> PMEM8 "pm0.0" |
0652   | DIMM1 <-+ +-v--+ | +---------+   +--------------+  +---------------+
0653   +-------+ +-+BUS0+-| +---------+   +--------------+  +----------------------+
0654   | DIMM2 <-+ +----+ +-> REGION1 +---> NAMESPACE1.0 +--> PMEM6 "pm1.0" | BTT1 |
0655   +-------+ |        | +---------+   +--------------+  +---------------+------+
0656   | DIMM3 <-+
0657   +-------+