Skip to content

Get initial FreeBSD support rolling - #3745

Draft
dwsuse wants to merge 1 commit into
linux-nvme:masterfrom
dwsuse:freebsd
Draft

Get initial FreeBSD support rolling#3745
dwsuse wants to merge 1 commit into
linux-nvme:masterfrom
dwsuse:freebsd

Conversation

@dwsuse

@dwsuse dwsuse commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Usually, porting to a new platform, architecture, or compiler uncovers generic problems throughout the codebase. The initial porting attempt to FreeBSD is no exception. We need to fix generic build dependencies and add dummy implementations for FreeBSD. These dummy implementations require further review, as some parts can and should be shared with Linux.

@dwsuse

dwsuse commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author
root@freebsd:~/nvme-cli # meson test -C .build
ninja: Entering directory `/root/nvme-cli/.build'
ninja: no work to do.
 1/41 nvme-cli:shared - array-util                         OK               0.01s
 2/41 nvme-cli:shared - base64                             OK               0.00s
 3/41 nvme-cli:shared - crc32                              OK               0.00s
 4/41 nvme-cli:shared - ini                                OK               0.00s
 5/41 nvme-cli:shared - parse-util                         OK               0.00s
 6/41 nvme-cli:shared - hash-util                          OK               0.00s
 7/41 nvme-cli:shared - string-util                        OK               0.01s
 8/41 nvme-cli:shared - io-util                            OK               0.01s
 9/41 nvme-cli:shared - net-util                           OK               0.00s
10/41 nvme-cli:shared - shr-assert                         OK               0.00s
11/41 nvme-cli:shared - fs-util                            OK               0.01s
12/41 nvme-cli:libnvme - check-public-symbols              OK               0.03s
13/41 nvme-cli:libnvme - cpp-dump                          OK               0.00s
14/41 nvme-cli:libnvme - cpp-misc                          OK               0.00s
15/41 nvme-cli:libnvme - uuid                              OK               0.00s
16/41 nvme-cli:libnvme - tree                              OK               0.00s
17/41 nvme-cli:libnvme - header/endian                     OK               0.00s
18/41 nvme-cli:libnvme - check-public-headers              OK               0.04s
19/41 nvme-cli:libnvme - header/fabrics                    OK               0.01s
20/41 nvme-cli:libnvme - header/ioctl                      OK               0.01s
21/41 nvme-cli:libnvme - header/lib                        OK               0.01s
22/41 nvme-cli:libnvme - header/lib-types                  OK               0.01s
23/41 nvme-cli:libnvme - header/mi                         OK               0.01s
24/41 nvme-cli:libnvme - header/nbft                       OK               0.01s
25/41 nvme-cli:libnvme - header/nvme-cmds                  OK               0.01s
26/41 nvme-cli:libnvme - header/nvme-cmds-base             OK               0.01s
27/41 nvme-cli:libnvme - header/nvme-cmds-fabrics          OK               0.01s
28/41 nvme-cli:libnvme - header/nvme-cmds-mi               OK               0.01s
29/41 nvme-cli:libnvme - header/nvme-cmds-nvm              OK               0.01s
30/41 nvme-cli:libnvme - header/nvme-cmds-zns              OK               0.01s
31/41 nvme-cli:libnvme - header/nvme-types                 OK               0.01s
32/41 nvme-cli:libnvme - header/nvme-types-base            OK               0.01s
33/41 nvme-cli:libnvme - header/nvme-types-fabrics         OK               0.01s
34/41 nvme-cli:libnvme - header/nvme-types-mi              OK               0.01s
35/41 nvme-cli:libnvme - header/nvme-types-nbft            OK               0.01s
36/41 nvme-cli:libnvme - header/nvme-types-nvm             OK               0.01s
37/41 nvme-cli:libnvme - header/nvme-types-zns             OK               0.01s
38/41 nvme-cli:libnvme - header/scan                       OK               0.01s
39/41 nvme-cli:libnvme - header/tree                       OK               0.01s
40/41 nvme-cli:libnvme - header/util                       OK               0.01s
41/41 nvme-cli:nvme-cli - command-metadata-schema          SKIP             0.04s   exit status 77

Ok:                40
Fail:              0
Skipped:           1

Full log written to /root/nvme-cli/.build/meson-logs/testlog.txt

@dwsuse dwsuse changed the title Get initial FreeBSD roling Get initial FreeBSD support rolling Aug 5, 2026
@igaw igaw mentioned this pull request Aug 6, 2026
@dwsuse
dwsuse marked this pull request as draft August 6, 2026 08:32
@dwsuse

dwsuse commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

I've merged all cleanup patches. That means the "only" thing for FreeBSD support is to add code to these dummy implementation. I will not do this. Thus I am asking for someone who wants add the missing pieces.

@bsdimp

bsdimp commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

I've been maintaining the FreeBSD nvme-cli port for years with a small shim library. It compiled most things. I implemented linux-compatible ioctls in FreeBSD, as well as moving to the linux naming convention for device nodes. The fork is at https://github.com/bsdimp/nmve-cli . The last version I ported was 2.11.

For that port, FreeBSD didn't have if_alg.h, so I made it a meson detected thing, created stubs for nvme-rpmb, commented out some things that needed bigger changes, Made using LC_MEASUREMENT optional, removed an unneeded endian.h, implemented an open wrapper to catch opening sysfs stuff (minimally), added a needed libgen.h include, removed a few asm/byteorder.h includes, fixed the micron and wdc support to remove linuxisms, fixed the SN340 support (independent of the os), and created small wrappers for converting the linuxisms into freeBSD generically at http://github/bsdimp/freebsd-nvme-shim.

* equivalent, so libnvme_alloc_huge() always takes the small-allocation
* posix_memalign() path regardless of size -- correct, just without the
* performance benefit of real huge pages.
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FreeBSD manages promotion to superpages automatically, so the performance penalties and benefits of huge pages are automatic. So it's unfair to say 'just without the performance benefits' here.

* mirrors lib-linux.c's approach without assuming Linux's "nvme%dn%d"
* naming scheme. Actual command submission is stubbed out in
* ioctl-freebsd.c.
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FreeBSD supports both nvme%dn%d and nvme%dns%d for some time now.

hdl->fd = LIBNVME_TEST_FD;

if (!strcmp(name, "NVME_TEST_FD64"))
hdl->ioctl_admin_state = IOCTL_STATE_IOCTL64;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FreeBSD does support the Linux ioctls, but does not support the *64 variants. In the past, these haven't been used by nvme-cli for anything I cared about.

#include <libnvme.h>

#include "private.h"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a spec for all these functions? They look to mirror the old sysfs walking that I too stubbed out.

{
char *state = c->state;

c->state = strdup("");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what state is supposed to be here?

__shr_unused libnvme_ctrl_t c,
__shr_unused int instance)
{
return -ENOTSUP;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for these.

Comment thread util/hash-freebsd.c Outdated
unsigned char *create_md5(unsigned char *data, int datalen)
{
return NULL;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of these are in FreeBSD libraries in the base.

Comment thread util/sighdl-freebsd.c Outdated
#include <stddef.h>

#include "sighdl.h"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to have a comment that FreeBSD is straight up POSIX for signals.

Comment thread nvme-pci-ids-freebsd.c Outdated
__u32 *vid, __u32 *did,
__u32 *subsys_vid, __u32 *subsys_did,
__u32 *class_code)
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sysfs_dir is what?

int libnvme_ctrl_load_phy_slot(__shr_unused struct libnvme_ctrl *c)
{
/* FreeBSD has no PCIe physical slot sysfs equivalent. */
return 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This is only obtainable if you parse the dmidecode / smbios data that's around, but without a nice wrapper.

Comment thread libnvme/src/nvme/ioctl-freebsd.c Outdated
__shr_public int libnvme_reset_subsystem(
__shr_unused struct libnvme_transport_handle *hdl)
{
return -ENOTSUP;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no subsystem level reset, so this is correct.

__shr_unused struct libnvme_transport_handle *hdl)
{
return -ENOTSUP;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NVME_RESET_CONTROLLER

__shr_unused struct libnvme_transport_handle *hdl)
{
return -ENOTSUP;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not one currently, so this is currect.

__shr_unused __u32 *nsid)
{
return -ENOTSUP;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NVME_GET_NSID

__shr_unused struct libnvme_transport_handle *hdl,
__shr_unused int block_size)
{
return -ENOTSUP;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, the FreeBSD driver handles this correctly by asking at open time.

__shr_public int libnvme_exec_admin_passthru(
__shr_unused struct libnvme_transport_handle *hdl,
__shr_unused struct libnvme_passthru_cmd *cmd)
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NVME_PASSTHROUGH_CMD on the right nvme device node (the non-namespace one) or the NVME_IOCTL_ADMIN_CMD command that has the same semantics as Linux.

__shr_unused struct libnvme_transport_handle *hdl,
__shr_unused struct libnvme_passthru_cmd *cmd)
{
return -ENOTSUP;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NVME_PASSTHROUGH_CMD on the right nvme device node (the namespace one) or the NVME_IOCTL_OP_CMD command that has the same semantics as Linux.

@bsdimp

bsdimp commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

I left several comments, but I won't have a ton of time to write this myself for a while. I do likely have time for questions and review. I tried to find the right folks to chat with when I heard about the Windows port, but didn't fallow up on all the leads because the problems of the day got in the way.

@igaw

igaw commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

I've been maintaining the FreeBSD nvme-cli port for years with a small shim library. It compiled most things. I implemented linux-compatible ioctls in FreeBSD, as well as moving to the linux naming convention for device nodes. The fork is at https://github.com/bsdimp/nmve-cli . The last version I ported was 2.11.

Thanks for the pointer. As far I can tell the current master is not far of to get native support for FreeBSD. The ioctl interface can just use the Linux implementation then. For nvme-pci devices the 32bit variant is good enough, the 64bit version is only necessary for fabrics. In this case we just disable the 64bit support on FreeBSD, that's easy. The interesting part is mostly, the sysfs replacement IMO. We have now an abstraction in libnvme the attribute layer which is on Linux sysfs and for Windows it uses nvme commands to read the attributes directly. I suppose this will be similar for FreeBSD.

For that port, FreeBSD didn't have if_alg.h, so I made it a meson detected thing, created stubs for nvme-rpmb, commented out some things that needed bigger changes, Made using LC_MEASUREMENT optional, removed an unneeded endian.h, implemented an open wrapper to catch opening sysfs stuff (minimally), added a needed libgen.h include, removed a few asm/byteorder.h includes, fixed the micron and wdc support to remove linuxisms, fixed the SN340 support (independent of the os), and created small wrappers for converting the linuxisms into freeBSD generically at http://github/bsdimp/freebsd-nvme-shim.

  • 665c13a wdc: On FreeBSD, get the timezone the same as with real glibc
    Is gated behind NVME_HAVE_TM_GMTOFF now
  • 46a5271 sn340: Add support
    I suppose this is a backport, nothing to do?
  • ffb4c34 nvme-cli: Make micron and wdc work on FreeBSD
    we touched this part during the Windows port, but likely it needs to addressed differently for FreeBSD, @bbusacker
  • 6172077 meson.build
    the whole build should be fixed in master
  • 91c101c Hack because LC_MEASUREMENT isn't on FreeBSD
    needs to fixed
  • 0067795 Add libgen.h for basename
    basename should be replaced shr_basename so it also works on Windows
  • 56863b3 Don't redfine u8.
    still there, needs to be fixed
  • 7be1b7a Don't redefine LITTLE_ENDIAN
    big endian and little endian macros are gated now
  • 0e1d960 nvme.h: endian.h isn't needed
    fixed by the Windows port
  • 21fe1b7 Don't nvme-rpmb.c when no AF_ALG
    fixed by using openSSL instead

So there only a few things left from your v2.11 port which are missing in master. I will look into getting all these changes into master.

And thanks for reviewing the patch, sorry it is ai slop... I asked to implement only empty dummies for an clean build on FreeBSD.

@igaw

igaw commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

I left several comments, but I won't have a ton of time to write this myself for a while. I do likely have time for questions and review. I tried to find the right folks to chat with when I heard about the Windows port, but didn't fallow up on all the leads because the problems of the day got in the way.

Thanks for trying to get people involved. I'll deal with the list above. Hooking up the ioctl part should also be straight forward if we can just reuse the Linux implementation (with 32bit mode only). Maybe we an even reuse more bits from Linux there. This PR contains the full set of function which are platform depended.

My only real question is what needs to be done for the attributes, is there also a sysfs combat implementation? If not, then we could just add the nvme commands for it (identify ctrl, identify ns, etc).

Add FreeBSD support to allow the project to build and do basic device
discovery/passthru on a different platform.

FreeBSD's nvme(4) driver implements the same "Linux compatible" NVMe
ioctls as the Linux kernel (NVME_IOCTL_ID, NVME_IOCTL_ADMIN_CMD,
NVME_IOCTL_IO_CMD, NVME_IOCTL_RESET), so ioctl-freebsd.c mirrors
ioctl-linux.c almost verbatim, including its 64-to-32-bit passthru
ioctl fallback (FreeBSD only implements the 32-bit ioctls).

FreeBSD has no sysfs, so tree-freebsd.c and attr-accessors-custom-
freebsd.c follow the Windows model instead: controller/subsystem
identity and namespace geometry are learned from Identify commands
rather than sysfs reads, and device enumeration in scan-freebsd.c
walks /dev for nvmeX/nvmeXnY nodes directly since nvme(4) already uses
Linux-compatible device names. PCI vendor/device IDs and a controller's
PCI address (used as its libnvme traddr) come from the
dev.nvme.<N>.%pnpinfo and dev.nvme.<N>.%location sysctls.

Verified on FreeBSD 15.1: full clean build, existing test suite (only
failure is a pre-existing, unrelated mkstemp-validation difference in
shared/tests/test-fs-util between FreeBSD's and glibc's libc), and
`nvme list`/`id-ctrl`/`id-ns`/`smart-log` against a real QEMU NVMe
device.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
@dwsuse

dwsuse commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

I've let claude just rebased and updated it to the latest master. There were a few significant changes in libnvme. And then asked to add the implementation to it and it got it even working:

root@freebsd:~/nvme-cli # .build/nvme list-subsys
nvme0 - NQN=nqn.2019-08.org.qemu:nvme-virtual-0
        hostnqn=nqn.2014-08.org.nvmexpress:uuid:00000000-0000-0000-0000-000000000000
\
 +- nvme0 pcie 0000:00:02.0
root@freebsd:~/nvme-cli # .build/nvme list-subsys -v
nvme0 - NQN=nqn.2019-08.org.qemu:nvme-virtual-0
        hostnqn=nqn.2014-08.org.nvmexpress:uuid:00000000-0000-0000-0000-000000000000
        iopolicy=
        model=undefined
        serial=
        firmware=
        type=nvm
\
 +- nvme0 pcie 0000:00:02.0
root@freebsd:~/nvme-cli # .build/nvme list
Node                  Generic               SN                   Model                                    Namespace  Usage                      Format           FW Rev
--------------------- --------------------- -------------------- ---------------------------------------- ---------- -------------------------- ---------------- --------
/dev/nvme0n1          nvme0n1               nvme-virtual-0       QEMU NVMe Ctrl                           0x1          1.07  GB /   1.07  GB    512   B +  0 B   11.0.2
root@freebsd:~/nvme-cli # .build/nvme id ctrl /dev/nvme0
NVME Identify Controller:
vid       : 0x1b36
ssvid     : 0x1af4
sn        : nvme-virtual-0
mn        : QEMU NVMe Ctrl
fr        : 11.0.2
...

So this is still a bit messy but working starting point.

@igaw

igaw commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

I think as soon we have #3660 figured out, this could go in and then let's improve it in tree. If it is not merged it will bit rot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants