Get initial FreeBSD support rolling - #3745
Conversation
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 |
|
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. |
|
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. | ||
| */ |
There was a problem hiding this comment.
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. | ||
| */ |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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" | ||
|
|
There was a problem hiding this comment.
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(""); |
There was a problem hiding this comment.
what state is supposed to be here?
| __shr_unused libnvme_ctrl_t c, | ||
| __shr_unused int instance) | ||
| { | ||
| return -ENOTSUP; |
| unsigned char *create_md5(unsigned char *data, int datalen) | ||
| { | ||
| return NULL; | ||
| } |
There was a problem hiding this comment.
Both of these are in FreeBSD libraries in the base.
| #include <stddef.h> | ||
|
|
||
| #include "sighdl.h" | ||
|
|
There was a problem hiding this comment.
Might want to have a comment that FreeBSD is straight up POSIX for signals.
| __u32 *vid, __u32 *did, | ||
| __u32 *subsys_vid, __u32 *subsys_did, | ||
| __u32 *class_code) | ||
| { |
| int libnvme_ctrl_load_phy_slot(__shr_unused struct libnvme_ctrl *c) | ||
| { | ||
| /* FreeBSD has no PCIe physical slot sysfs equivalent. */ | ||
| return 0; |
There was a problem hiding this comment.
Yes. This is only obtainable if you parse the dmidecode / smbios data that's around, but without a nice wrapper.
| __shr_public int libnvme_reset_subsystem( | ||
| __shr_unused struct libnvme_transport_handle *hdl) | ||
| { | ||
| return -ENOTSUP; |
There was a problem hiding this comment.
There's no subsystem level reset, so this is correct.
| __shr_unused struct libnvme_transport_handle *hdl) | ||
| { | ||
| return -ENOTSUP; | ||
| } |
| __shr_unused struct libnvme_transport_handle *hdl) | ||
| { | ||
| return -ENOTSUP; | ||
| } |
There was a problem hiding this comment.
There's not one currently, so this is currect.
| __shr_unused __u32 *nsid) | ||
| { | ||
| return -ENOTSUP; | ||
| } |
| __shr_unused struct libnvme_transport_handle *hdl, | ||
| __shr_unused int block_size) | ||
| { | ||
| return -ENOTSUP; |
There was a problem hiding this comment.
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) | ||
| { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
|
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 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.
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. |
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>
|
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. |
|
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. |
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.