We should improve libzfs somewhat

14 points by tomhukins


jclulow

FWIW, libzfs.so.1 (and its companion, libzpool.so.1) is definitely not the application interface. It’s just a private implementation detail of zpool(8) and zfs(8), and potentially some syseventd(8) and fmd(8) modules. It’s definitely not a Committed interface, and shouldn’t become one.

The libzfs_core.so.1 interface is, as noted in the article, intended to provide a Committed interface with API and ABI stability. It’s not clear why work on it essentially stalled, but I think the answer is probably that good stable library design is difficult, and in the case of ZFS generally the commands are actually enough.

The commands have stable, documented output. There’s an easily machine-parseable way to get details about datasets, snapshots, pools, etc (this was true long before the JSON work was done, too). I have worked on lots of programs that automate the management of ZFS, and I don’t think that running the tools (rather than using a library) is actually an impediment. In fact, it has some key advantages; e.g., you don’t need to give your management process the elevated privileges it would need to make ioctl(2) calls to the kernel to manipulate the file system, you can instead use a facility like rbac(7) profiles and pfexec(1) to provide relatively constrained access, such as via the ZFS File System Management or ZFS Storage Management profiles.

I think nvlists are actually a very reasonable way to express an interface that has such complicated requirements. They’re strongly typed, and they’re amenable to ergonomic interfaces in higher level languages like Rust (you could serialise and deserialise them with serde, for example) or Go or Python or whatever else. They also make it much easier to provide ABI stability: ensuring C structs don’t accidentally change shape over time is notoriously difficult, as the source doesn’t show you implicit things like padding, alignment, or the overall size of the struct, and you can never reorder the fields in the source even if it would help make it clearer. They’re also self-describing, which means you can easily dump them out in the debugger; e.g., MDB has an ::nvlist dcmd that can, from just the pointer, show you the contents of a given nvlist_t.

I was pretty uncomfortable with channel programs when they were integrated originally, and I’m not sure my feelings have improved over time. They allow a turing complete program to be injected into the kernel and run in a relatively high priority context, and there’s essentially (by construction) nothing you can do to make that both completely safe against, say, infinite loops, and also correct (e.g., by not selecting an arbitrary timeout after which you just abort the thing).

The article also seems to conflate naming the arguments in C header files with documentation, but the names are intentionally absent from the headers: they’re not syntactically necessary, and putting names in the header both makes the header bulkier than it needs to be, and also provides a source of “split brain” between the declaration in the header and the actual definition of the function somewhere else. Documentation for these sorts of libraries is provided in manual pages, rather than in the header.

As an aside, we do not capitalise “illumos” – and the reference to “old Solaris” made me think of the story about Cary Grant receiving a telegram (billed, ostensibly, by the word) from a reporter that inquired HOW OLD CARY GRANT?, to which he replied: OLD CARY GRANT FINE. HOW YOU?

cyberia

I like this post, but for someone who has such attention to detail as to be able to comment on C library design, I’m disappointed that the author consistently can’t spell the word “its”.