[Libguestfs] [libnbd PATCH 1/2] api: Better use of nbd_internal_reset_size_and_flags

Laszlo Ersek lersek at redhat.com
Tue Aug 30 11:16:02 UTC 2022


On 08/25/22 17:05, Eric Blake wrote:
> On Thu, Aug 25, 2022 at 12:13:42PM +0200, Laszlo Ersek wrote:
>> [...]

> The design background does play a big role.  When we first started
> libnbd, we did not have an easy way to write an API that would take a
> string vector as a single argument that the generator could then
> translate nicely into C, OCaml, and Python APIs (this was before we
> later added golang translations).

Thanks for the explanation. I didn't expect these two principles to have
driven the design (generability, and long-term convenience calls). I
think the more usual (albeit likely less programmer-friendly) approach
is to (a) expose the minute details and let the end-programmer deal with
them, (b) let people write / maintain other-than-C language wrappers
manually.

> noticed that there are really two different groups of client states to
> track after server interaction:
> 
> export information (nbd_get_size, nbd_is_read_only, nbd_can_trim, ...)
> [...]
> context mappings (nbd_can_meta_context)
> [...]

This is a huge amount of nuances -- I remember being in a position
where, as a long-term maintainer, I could collect, or at least
understand, this many bits intuitively, but that doesn't work for me as
a newcomer to a project. So please try to write surgical, super-focused
patches, if I'm to have a chance at reviewing them. :)

> Maybe this will help. NBD_OPT_LIST_META_CONTEXT says "what context
> names does the server support, where the server can disregard the
> export name if that makes sense, and where both directions can use
> wildcards to allow the server to advertise a family of export names
> and the client to ask for more details within that family".  With
> qemu-nbd as server, LIST_META_CONTEXT([], "") (the empty vector) might
> currently cause the server to reply with ["base:allocation",
> "qemu:dirty-bitmap:a", "qemu:dirty-bitmap:b"] (all the contexts it
> specifically supports on the export ""), while
> LIST_META_CONTEXT(["qemu:"], "") would only reply with
> ["qemu:dirty-bitmap:a", "qemu:dirty-bitmap:b"].  But it would also
> have been possible for qemu-nbd to reply to the empty vector query
> with ["base:allocation", "qemu:"] ("base:allocation" is supported on
> all exports, regardless of name, but instead of spelling out
> individual "qemu:..." contexts available for the specific context,
> returning the wildcard "qemu:" means that the client must do a further
> LIST_META_CONTEXT to learn about specific contexts for a given
> export).

I don't understand why this is useful, as a part of the protocol. It
seems difficult to program a robust client if the server is permitted to
respond in so different styles!

Maybe the output of this operation was not (primarily) meant to be
consumed by a program (but humans that are happy to iterate and to
construct new queries on the spot).

> Conversely, NBD_OPT_SET_META_CONTEXT does not use wildcards, in either
> the client or the server direction.  It is documented as strictly "the
> client wants these contexts for this export; the server must supply a
> context-to-id mapping for the ones it supports, and that mapping is
> then valid until the next NBD_OPT_SET_META_CONTEXT, NBD_OPT_STARTTLS,
> or use of NBD_OPT_GO with a different export name".

Hmm, OK.

> 
> The nbd_opt_list() function is trying to learn as much information
> about a specific export: what it its size and readonly status (from
> NBD_OPT_LIST), and what contexts can it support (here,
> NBD_OPT_SET_META_CONTEXT guarantees correct answers, but is rather
> heavy-handed in setting server state; NBD_OPT_LIST_META_CONTEXT might
> return wildcards instead of exact answers, but for nbd_opt_info(),
> that's probably good enough).  Then again, since I wrote it without a
> callback function, the only way to query which contexts is via
> nbd_can_meta_context(), which requires the name-to-id mapping, which
> we get from NBD_OPT_SET_META_CONTEXT.
> 
> Of course, once I add nbd_set_request_meta_context(), we can skip the
> NBD_OPT_SET_META_CONTEXT done by nbd_opt_info(), and let the user
> manually use nbd_opt_list_meta_context() for its own stateless
> NBD_OPT_LIST_META_CONTEXT query of the supported contexts.
> 
> So it may also be worth a new API:
> 
> nbd_opt_info_with_contexts(export_name, vector_of_queries, callback)
> 
> to be used in place of
> 
> nbd_add_meta_context(context)
> nbd_opt_info(export_name)
> nbd_can_meta_context(context)
> 
> for less stateful pollution.

Given that we need to keep the old APIs for compatibility's sake, I
think new APIs should not be introduced unless they add a new
capability. There is already a multitude of APIs.

> 
>>
>> - NBD_OPT_INFO in particular looks like a useless opcode.
> 
> Useless when you already know what export you want to connect to.  But
> useful during the 'nbdinfo' app when you want to learn as much as
> possible about every export exposed by a single nbd server, while
> still remaining in negotiation after each export thus queried.

Such "discovery" looks useful for humans, but is it useful to client
programs other than nbdinfo?

> 
>> NBD_OPT_SET_META_CONTEXT handles the filtering (intersection) and
>> mapping to numeric IDs. NBD_OPT_GO transitions the server to the "ready"
>> state (completes negotiation). So those two look useful. I don't
>> understand what the precise responsibility is that *only* NBD_OPT_INFO
>> can cover. The manual at <https://libguestfs.org/nbd_opt_info.3.html>
>> says that nbd_opt_info() enables export size querying (for example), but
>> that kind of querying is just as possible without nbd_opt_info(); only
>> nbd_set_opt_mode() is needed -- see the example code at
>> <https://libguestfs.org/nbd_set_opt_mode.3.html>.
> 
> That example is only able to print what NBD_OPT_LIST returns (the
> export name, and any description the server provides) - some servers
> might provide the export size in the human-readable description, but
> the only way to get a machine-readable readout of each size is to
> further call NBD_OPT_INFO on each name returned by NBD_OPT_LIST.
> nbd_set_opt_mode() is what lets it be possible to call nbd_opt_list(),
> but it still requires nbd_opt_list() before you can use nbd_get_size()

(s/nbd_opt_list/nbd_opt_info/ ?)

> while still remaining in negotiation mode.

Aha! So the trick is that the example code uses nbd_get_size() *after*
nbd_opt_go(), but we may want to call nbd_get_size() before entering the
"ready" state.

[...]

I've read the rest too -- it's a lot to digest. I've nothing more to add
at this moment.

Thank you!
Laszlo


More information about the Libguestfs mailing list