.. _sec-contributing-assumptions:

==================
 Code Assumptions
==================

These are notes on contracts and assumptions in the **xNVMe** codebase. These
are written down separate from the code for more convenient reading. Thus,
whenever code-changes are made that alter assumptions and contracts described
herein, then this document must be updated as well as part of the change-set.

The device handle contract
==========================

Device handles are opaque pointers of type :c:struct:`struct
xnvme_dev`. Device handles are obtained via the public **xNVMe**
API call :c:func:`xnvme_dev_open()`, and released via a call
to :c:func:`xnvme_dev_close()`.

The entities involved in the implementation of this and their individual
responsibility in setting up the data-structure is described in this section
here.

These functions are implemented in the library-private **device module**
(``xnvme_dev.c``). The **device module** is responsible for allocating
and initializing the data-structure associated with and encapsulating the
device handle upon :c:func:`xnvme_dev_open()` and freeing these resources
upon :c:func:`xnvme_dev_close()`.

Device handles are system interface specific; file-descriptors on UNIX-like
systems, opaque pointers on Windows, typed pointers in user-space drivers
such as SPDK, etc. Thus, the **device module** is only responsible for generic
initialization, it delagates these system specifics to the **backend module**
(``xnvme_be.c``).

The library-private **backend module** in turn, defines a **backend
interface** (``xnvme_be.h``) and implements a **backend factory**
(:c:func:`xnvme_be_factory()`). The **backend factory** knows of all
**backends** implementing the **backend interface**.

Thus, to obtain a system specific handle it delegates to each **backend**,
in turn, the implementation of obtaining a system interface specific device
handle, for a given **device identifier**, is handled by the first **backend
implementation** (``xnvme_be_*_dev.c``) capable of producing a handle.

In other words, the **backend factory** chooses the first **backend** capable
of returning a system interface specific device handle and the system interface
specific handle produced by the **backend**.

The entities described above are those involved in the setup of a xNVMe
device handle. The xNVMe device handle is opaque, that is the details of its
representation is hidden from the user. Thus, functions are provided to retrieve
data about a given device handle.

However, described here are the details on how the representation is
constructed by the library-private: **device module**, **backend module**,
and instances of the **backend interface** implementation aka **backends**
(``xnvme_be_{spdk,vfio,linux,fbsd,windows}_*.c```).

Identification and Geometry
---------------------------

The structure encapsulating the **device handle** is library-private, however,
for contributions to **backends**, **device module**, and related, then a bit of
info on how it is setup is useful, it is provided below.

.. code-block:: bash

  # Assigned by xnvme_be_factory()
  dev.be

  # The backend-factory copies the opts and adjusts them to the options
  # describing the backend, thus showing which "configuration" it ended up with
  dev.opts 

  # Initialized by xnvme_dev_open() using helper xnvme_ident_from_uri(), then
  # backends further manipulate the structure
  dev.ident 

  # These are setup by the backend as it is "opening" the device, here it might
  # do simple things such as fstat() on Linux to determine whether the device
  # handle is a block-device or a char-device to indicate the ident.dtype
  dev.ident.dtype

  # The device module assigns this in the identification-helper _dev_idfy()
  dev.ident.subnqn

  # Each backend-implementation sets these up after they have created a
  # system-interface-specific device handle
  dev.ident.dtype
  dev.ident.nsid
  dev.ident.csi

  dev.is_derived # setup by xnvme_dev_get_*() access after calling xnvme_dev_derive_geometry()

  # These are assigned by the device module at "identification-time"
  dev.id.ctrlr
  dev.id.ns
  dev.idcss.ctrlr
  dev.idcss.ns
  dev.attempted_dev_idfy

  # Populated by the device module using the helper xnvme_dev_derive_geometry()
  dev.geo					

  # Set by xnvme_dev_derive_geometry()
  dev.attempted_derive_geo
