Library Usage Notes

The essence of xNVMe is an interface that enables you to command a device to do something. This is a achieved via a command-interface with asynchronous as well as synchronous semantics. In pseudo-code, you get a device-handle by opening it:

dev = xnvme_dev_open("/dev/nvme0n1");

To send a command, you need a command context, for synchronous execution, then you retrieve a command-context from the device:

# Get a synchronous command context
ctx = xnvme_cmd_ctx_from_dev(dev);

# Submit and wait for completion
res = xnvme_cmd_pass(ctx, cmd, ...);

For asynchronous execution, then you get the command context from a queue:

# Get an asynchronous command context
ctx = xnvme_cmd_ctx_from_queue(queue);

# Submit the command
res = xnvme_cmd_pass(ctx, cmd, ...);

# Process at least 'n' commands, n can be 0
res = xnvme_queue_poke(queue, n);

# Wait for all
res = xnvme_queue_drain(queue);

There are more details to the use of the library. E.g. what is a command, how do you construct and how do you allocate and provide data for the command to work with? And how do you setup queues, provide callback-functions, and callback-function arguments?

However, that is just boiler-plate code and designed to make it look and feel familiar.

When synchronous, then there is less things to do since xnvme_cmd_pass is blocking until the command has completed or if it failed submitting.

When using asynchronous semantics, then there is more things to do, you have to setup a queue, and poll/wait and implement a call-back function if you want to do something specific to the command that completed. This is because the submission and completion has been split up.

However, the pseuod-code above is the gist of the library, open a device, get a command context and send a command.

Backends

Command Interfaces

Return Values and Status Codes

The xnvme_cmd functions signal errors using the standard errno thread-local variable and a return value of -1. To gain more insights into what went wrong in a command, use the optional xnvme_cmd_ctx parameter that all xnvme_cmd functions take. When supplied, the xnvme_cmd_ctx will contain the NVMe status code in the status field.

Note that while the spdk backend has a one-to-one correspondence between what is in the xnvme_cmd_ctx and what is reported by the device, the Linux, backend will transform certain errors from the kernel into their NVMe equivalents.

This is because certain ioctl calls may return -1 and Invalid Argument without actually sending a command to the device. To align the backends with each other, such an error will be transformed into the NVMe equivalent, if possible. For example, Invalid Argument will be transformed into the NVMe status code Invalid Field in Command and set that in the given xnvme_cmd_ctx.

TODO: add references to the C API

Memory Management

When using the xnvme_cmd option XNVME_CMD_SGL, then use these functions to manage the Scather / Gather Lists.

Asynchronous Interface

When using the xnvme_cmd option XNVME_CMD_ASYNC, then use these functions to steer the asynchronous mechanics.

Pretty-Printing

Every structure has a pretty-printer function. Even the opaque ones, e.g. xnvme_dev has the printer function xnvme_dev_pr(). By convention they are named the same as the structure plus a _pr postfix.

The printers all take an opts parameter which controls how the structure should be printed, the current default is YAML representation.