11<!-- SPDX-License-Identifier: GPL-2.0-only -->
2- # Contributing to the NVM-e CLI
2+ # Contributing to nvme-cli and libnvme
33
44Here you will find instructions on how to contribute to the NVM-Express command
5- line interface.
5+ line interface and the libnvme library .
66
77Contributions and new ideas are most welcome!
88
@@ -14,13 +14,159 @@ under the [GPLv2-style License used for the NVMe CLI](https://github.com/linux-n
1414Because there are a few files licensed under GPL-2.0-only, the whole
1515project is tagged as GPL-2.0-only and not as GPL-2.0-or-later.
1616
17- ### Code Contributions
17+ ## API naming conventions
1818
19- Please feel free to use the github forums to ask for comments & questions on
20- your code before submitting a pull request. The NVMe CLI project uses the
21- common * fork and merge* workflow used by most GitHub-hosted projects.
19+ ### Spec-mirroring definitions (` nvme_ ` / ` nvmf_ ` )
2220
23- #### Commit conventions
21+ Types, structs, and enums that directly mirror the NVMe specifications use the
22+ short ` nvme_ ` (base spec) and ` nvmf_ ` (NVMe-oF spec) prefixes. These live in
23+ ` libnvme/src/nvme/types.h ` and ` libnvme/src/nvme/cmds.h ` and reflect the
24+ specification naming — they are data-layout definitions, not library API.
25+
26+ ### libnvme public API (` libnvme_ ` / ` libnvmf_ ` )
27+
28+ This is where the naming convention is enforced. libnvme is a shared library
29+ with a stable public ABI, so every public symbol must carry the correct prefix
30+ so that callers can immediately tell what they are working with.
31+
32+ | Prefix | Scope | Examples |
33+ | --------| -------| ---------|
34+ | ` libnvme_ ` | Common NVMe (PCIe and NVMe-oF) | ` libnvme_open() ` , ` libnvme_create_global_ctx() ` , ` libnvme_first_host() ` , ` libnvme_ctrl_identify() ` |
35+ | ` libnvmf_ ` | NVMe-oF only | ` libnvmf_connect_ctrl() ` , ` libnvmf_add_ctrl() ` , ` libnvmf_get_discovery_log() ` , ` libnvmf_trtype_str() ` |
36+
37+ The split is enforced by two separate linker version scripts:
38+ ` libnvme/src/libnvme.ld ` exports all ` libnvme_* ` symbols and
39+ ` libnvme/src/libnvmf.ld ` exports all ` libnvmf_* ` symbols. Both are passed to
40+ the linker when building ` libnvme.so ` .
41+
42+ When contributing new functions to libnvme, choose the prefix based on scope:
43+ - Use ` libnvme_ ` if the function applies to both PCIe and NVMe-oF controllers.
44+ - Use ` libnvmf_ ` if the function is specific to NVMe-oF (fabrics transport,
45+ discovery, connect/disconnect).
46+
47+ ## Adding commands and plugins
48+
49+ You may wish to add a new command or possibly an entirely new plug-in
50+ for some special extension outside the spec.
51+
52+ This project provides macros that help generate the code for you. If
53+ you're interested in how that works, it is very similar to how trace
54+ events are created by Linux kernel's 'ftrace' component.
55+
56+ ### Add a command to the existing built-in
57+
58+ The first thing to do is define a new command entry in the command
59+ list. This is declared in nvme-builtin.h. Simply append a new "ENTRY" into
60+ the list. The ENTRY normally takes three arguments: the "name" of the
61+ subcommand (this is what the user will type at the command line to invoke
62+ your command), a short help description of what your command does, and the
63+ name of the function callback that you're going to write. Additionally,
64+ you can declare an alias name of the subcommand with a fourth argument, if
65+ needed.
66+
67+ After the ENTRY is defined, you need to implement the callback. It takes
68+ four arguments: argc, argv, the command structure associated with the
69+ callback, and the plug-in structure that contains that command. The
70+ prototype looks like this:
71+
72+ ``` c
73+ int f (int argc, char ** argv, struct command * command, struct plugin * plugin);
74+ ```
75+
76+ The argc and argv are adjusted from the command line arguments to start
77+ after the sub-command. So if the command line is "nvme foo --option=bar",
78+ the argc is 1 and argv starts at "--option".
79+
80+ You can then define argument parsing for your sub-command's specific
81+ options then do some command-specific action in your callback.
82+
83+ ### Add a new plugin
84+
85+ The nvme-cli provides macros to make defining a new plug-in simpler. You
86+ can certainly do all this by hand if you want, but it should be easier
87+ to get going using the macros. To start, first create a header file
88+ to define your plugin. This is where you will give your plugin a name,
89+ description, and define all the sub-commands your plugin implements.
90+
91+ The macros must appear in a specific order within the header file. The following
92+ is a basic example on how to start this:
93+
94+ File: foo-plugin.h
95+ ```c
96+ #undef CMD_INC_FILE
97+ #define CMD_INC_FILE plugins/foo/foo-plugin
98+
99+ #if !defined(FOO) || defined(CMD_HEADER_MULTI_READ)
100+ #define FOO
101+
102+ #include "cmd.h"
103+
104+ PLUGIN(NAME("foo", "Foo plugin"),
105+ COMMAND_LIST(
106+ ENTRY("bar", "foo bar", bar)
107+ ENTRY("baz", "foo baz", baz)
108+ ENTRY("qux", "foo qux", qux)
109+ )
110+ );
111+
112+ #endif
113+
114+ #include "define_cmd.h"
115+ ```
116+
117+ In order to have the compiler generate the plugin through the xmacro
118+ expansion, you need to include this header in your source file, with
119+ a pre-defining macro directive to create the commands.
120+
121+ To get started from the above example, we just need to define "CREATE_CMD"
122+ and include the header:
123+
124+ File: foo-plugin.c
125+ ``` c
126+ #include " nvme.h"
127+
128+ #define CREATE_CMD
129+ #include " foo-plugin.h"
130+ ```
131+
132+ After that, you just need to implement the functions you defined in each
133+ ENTRY, then append the object file name to the meson.build "sources".
134+
135+ ### Updating the libnvme accessor functions
136+
137+ libnvme exposes auto-generated getter/setter accessor functions for its
138+ ABI-stable opaque structs. Two sets of accessors are maintained:
139+
140+ | Set | Input header | Generated files |
141+ | -----| -------------| -----------------|
142+ | Common NVMe | ` libnvme/src/nvme/private.h ` | ` src/nvme/accessors.{h,c} ` , ` src/accessors.ld ` |
143+ | NVMe-oF | ` libnvme/src/nvme/private-fabrics.h ` | ` src/nvme/accessors-fabrics.{h,c} ` , ` src/accessors-fabrics.ld ` |
144+
145+ The generated ` .h ` and ` .c ` files are committed to the source tree and are
146+ ** not** regenerated during a normal build. To regenerate after modifying a
147+ ` /*!generate-accessors*/ ` struct:
148+
149+ ``` shell
150+ $ meson compile -C .build update-accessors
151+ ```
152+
153+ See [ ` libnvme/README.md ` ] ( libnvme/README.md#accessor-generation ) for full
154+ details, including how to maintain the ` .ld ` version-script files.
155+
156+ ## Submitting changes
157+
158+ There are two ways to send code changes to the project. The first one
159+ is by sending the changes to
[email protected] . The
160+ second one is by posting a pull request on Github. In both cases
161+ please follow the Linux contributions guidelines as documented in
162+ [ Submitting patches] ( https://docs.kernel.org/process/submitting-patches.html ) .
163+
164+ That means the changes should be a clean series (no merges should be
165+ present in a Github PR for example) and every commit should build.
166+
167+ See also [ How to create a pull request on GitHub] ( https://opensource.com/article/19/7/create-pull-request-github ) .
168+
169+ ### Commit conventions
24170
25171The project follows the Linux kernel mailing list workflow,
26172thus commit messages should be structured like this:
@@ -42,6 +188,39 @@ Show new contributors the project's commit guidelines
42188Signed-off-by: John Doe <[email protected] > 43189```
44190
45- ### Bug Reports
191+ ### How to clean up your series before creating a PR
192+
193+ This example here assumes the changes are in a branch called
194+ fix-something, which branched away from master in the past. In the
195+ meantime the upstream project has changed, hence the fix-something
196+ branch is not based on the current HEAD. Before posting the PR, the
197+ branch should be rebased on the current HEAD and retest everything.
198+
199+ For example, rebasing can be done by the following steps
200+
201+ ``` shell
202+ # Update master branch
203+ # upstream == https://github.com/linux-nvme/nvme-cli.git
204+ $ git switch master
205+ $ git fetch --all
206+ $ git reset --hard upstream/master
207+
208+ # Make sure all dependencies are up to date and make a sanity build
209+ $ meson subprojects update
210+ $ ninja -C .build
211+
212+ # Go back to the fix-something branch
213+ $ git switch fix-something
214+
215+ # Rebase it to the current HEAD
216+ $ git rebase master
217+ [fixup all merge conflicts]
218+ [retest]
219+
220+ # Push your changes to Github and trigger a PR
221+ $ git push -u origin fix-something
222+ ```
223+
224+ ## Bug Reports
46225
47226Bugs for the NVM Library project are tracked in our [ GitHub Issues Database] ( https://github.com/linux-nvme/nvme-cli/issues ) .
0 commit comments