ndctl

repository·main·Indexed 43 days ago

https://github.com/pmem/ndctl

A utility library for managing the libnvdimm (non-volatile memory device) subsystem in the Linux kernel.

Tokens
2.2K
Snippets
7
Records
9
Agent score
54%

What's inside ndctl

  1. Build and install ndctl

    main

    To build ndctl from source, use the meson build system.

    Build steps

    1. Setup the build directory:
      meson setup build
    2. Compile the project:
      meson compile -C build

    Installation

    To install the built binaries to your system:

    meson install -C build

    Dependencies

    Ensure you have the required build dependencies installed. You can find the list of required packages in the BuildRequires: lines of the ndctl.spec.in file in the repository.

    meson setup build;
    meson compile -C build;
    
    # Optionally, to install:
    meson install -C build
  2. Set up the environment for ndctl unit tests

    main

    Running meson test requires specific kernel modules (like nfit_test.ko) to be loaded. This process involves building and installing test modules from the kernel source.

    1. Kernel Configuration

    For kernels < v4.8, you must configure the kernel to make memory available to the Contiguous Memory Allocator (CMA) to emulate DAX. Use either:

    • CONFIG_DMA_CMA=y and CONFIG_CMA_SIZE_MBYTES=200 in the kernel config.
    • cma=200M on the kernel command line.

    2. Required Kernel Config Options

    Ensure your kernel configuration includes the following options to support NVDIMM and DAX testing:

    CONFIG_X86_PMEM_LEGACY=m
    CONFIG_ZONE_DEVICE=y
    CONFIG_LIBNVDIMM=m
    CONFIG_BLK_DEV_PMEM=m
    CONFIG_BTT=y
    CONFIG_NVDIMM_PFN=y
    CONFIG_NVDIMM_DAX=y
    CONFIG_DEV_DAX_PMEM=m
    CONFIG_FS_DAX=y
    CONFIG_EXT4_FS=m
    CONFIG_XFS_FS=m
    CONFIG_DAX=m
    CONFIG_DEV_DAX=m
    CONFIG_ENCRYPTED_KEYS=y
    CONFIG_NVDIMM_SECURITY_TEST=y
    CONFIG_STRICT_DEVMEM=y
    CONFIG_IO_STRICT_DEVMEM=y
    CONFIG_ACPI_NFIT=m
    CONFIG_NFIT_SECURITY_DEBUG=y
    CONFIG_MEMORY_FAILURE=y
    CONFIG_MEMORY_HOTPLUG=y
    CONFIG_MEMORY_HOTREMOVE=y
    CONFIG_TRANSPARENT_HUGEPAGE=y

    3. Install Dependencies (Fedora)

    dnf install e2fsprogs xfsprogs parted jq trace-cmd hostname fio fio-engine-dev-dax

    4. Build and Install Test Modules

    Build and install the libnvdimm test modules in this specific order to ensure they are available before depmod runs:

    make M=tools/testing/nvdimm
    sudo make M=tools/testing/nvdimm modules_install
    sudo make modules_install

    5. Running Tests

    Run the tests using meson:

    meson test -C build

    Or, if ndctl was built with -Dtest=enabled, use:

    ndctl test

    Destructive Tests

    To run tests that may clobber existing pmem configurations and data, enable the destructive option:

    meson configure -Dtest=enabled -Ddestructive=enabled build
  3. Troubleshoot skipped ndctl unit tests

    main

    If meson test skips tests and reports that nfit_test is unavailable or that a production version of a module is being used instead of the test version, follow these steps:

    Override depmod policy

    If your test modules are located in the modules 'extra' directory, you can override the default depmod policy by creating a file in /etc/depmod.d/ with the following content:

    override nfit * extra
    override device_dax * extra
    override dax_pmem * extra
    override dax_pmem_core * extra
    override dax_pmem_compat * extra
    override libnvdimm * extra
    override nd_btt * extra
    override nd_e820 * extra
    override nd_pmem * extra

    Alignment workaround for nfit_test

    The nfit_test module emulates pmem using vmalloc(), which can break assumptions regarding physically contiguous memory. To avoid issues caused by this, use the --align=4K option when creating a namespace:

    ndctl create-namespace --align=4K ...
  4. Execute subcommands with main_handle_internal_command

    main

    The main_handle_internal_command function is used to dispatch execution to a specific subcommand defined in the cmds array.

    It includes a convenience feature: if a user runs <binary> <cmd> --help, the function internally transforms this into <binary> help <cmd> to trigger the help mechanism for that specific command.

    It uses run_builtin to execute the command's function pointer based on the prog type (either PROG_NDCTL or PROG_DCD).

    void main_handle_internal_command(int argc, const char **argv, void *ctx, struct cmd_struct *cmds, int num_cmds, enum program prog);
  5. Handle command-line options and internal commands

    main

    The utility provides two primary functions for managing the CLI lifecycle:

    1. main_handle_options: Processes top-level command-line arguments and options. It requires the argument vector (argv), argument count (argc), a usage message, an array of cmd_struct definitions, and the number of commands.
    2. main_handle_internal_command: Handles the execution of subcommands once the primary program context is established. It requires the argument count, argument vector, a pointer to the context (void *ctx), the command array, the number of commands, and the enum program type.

    Available enum program values:

    • PROG_NDCTL
    • PROG_DAXCTL
    • PROG_CXL
    int main_handle_options(const char ***argv, int *argc, const char *usage_msg,
    		struct cmd_struct *cmds, int num_cmds);
    
    void main_handle_internal_command(int argc, const char **argv, void *ctx,
    		struct cmd_struct *cmds, int num_cmds, enum program prog);
  6. Define command structures for ndctl, daxctl, and cxl

    main

    The ndctl command-line tool uses a struct cmd_struct to map command names to their respective handler functions. Depending on the program type, the handler function signature varies to accept the appropriate context pointer (ndctl_ctx, daxctl_ctx, or cxl_ctx).

    To define a new command, populate a struct cmd_struct with the command string and a pointer to a function matching one of these signatures:

    • int (*n_fn)(int, const char **, struct ndctl_ctx *ctx) for PROG_NDCTL
    • int (*d_fn)(int, const char **, struct daxctl_ctx *ctx) for PROG_DAXCTL
    • int (*c_fn)(int, const char **, struct cxl_ctx *ctx) for PROG_CXL
    struct cmd_struct {
    	const char *cmd;
    	union {
    		int (*n_fn)(int, const char **, struct ndctl_ctx *ctx);
    		int (*d_fn)(int, const char **, struct daxctl_ctx *ctx);
    		int (*c_fn)(int, const char **, struct cxl_ctx *ctx);
    	};
    };
  7. Run a command via run_builtin

    main

    The run_builtin function is an internal helper that executes the function pointer associated with a cmd_struct.

    It handles the distinction between different program types via the enum program prog parameter:

    • If prog == PROG_NDCTL, it calls the command's n_fn member.
    • Otherwise, it calls the command's d_fn member.

    After the command function returns, run_builtin performs cleanup on stdout, including flushing and closing it. It is designed to gracefully handle cases where stdout might be a pipe or socket, but it will report errors for standard file writes or if fflush/fclose fails.

  8. Handle command-line options with main_handle_options

    main

    The main_handle_options function processes global command-line flags before a specific subcommand is executed. It iterates through the arguments and handles standard flags like --help, --version, and --list-cmds.

    Supported global flags:

    • --help or -h: Displays the usage message.
    • --version or -v: Displays the version information.
    • --list-cmds: Prints a list of available commands (excluding internal/test commands like create-nfit, test, and bat) and exits.

    If an unknown option is encountered, it prints an error to stderr and calls usage().

    int main_handle_options(const char ***argv, int *argc, const char *usage_msg, struct cmd_struct *cmds, int num_cmds);
  9. Display man pages for commands

    main

    Use help_show_man_page to display the manual page for a specific command. This function takes the command name, the name of the utility, and the name of the viewer to be used (e.g., "man").

    int help_show_man_page(const char *cmd, const char *util_name,
    		const char *viewer);