Skip to content

Instantly share code, notes, and snippets.

@vpodzime
Created September 1, 2015 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vpodzime/008bf30c7d78079e0036 to your computer and use it in GitHub Desktop.
Save vpodzime/008bf30c7d78079e0036 to your computer and use it in GitHub Desktop.
design draft for the libblockdev's multiplugin support

[Design Draft] libblockdev's multiplugin support

With the LVM DBus API being almost a reality comes the need for libblockdev to start supporting multiple plugins providing the same functionality. In this particular example, the current lvm plugin using the lvm utility(ies) should be forked as a new lvm-dbus plugin that would use the LVM DBus API, but both should be supported and maintained in the near future because the LVM DBus API may contain serious bugs or it can be unavailable on some systems, etc.

Right now, the user code using libblockdev can specify so-names of shared objects that should be used as plugins. So if libbd_lvm_dbus.so is requested for the LVM plugin, it will be loaded instead of the default libbd_lvm.so file. However, this is suboptimal, because it requires the user code to make this decision instead of just giving it a way to do it and there's no fallback in case the libbd_lvm_dbus.so file cannot be loaded. What I believe should be our goal is to make the availability of the plugins determine which ones should be used with fallbacks in case something goes wrong. IOW, if the libblockdev-lvm-dbus package is installed, the libbd_lvm_dbus.so shared object should be the preferred one, but if it fails to load (for whatever reason), the original libbd_lvm.so file should be used as a fallback. And that all without the user code even knowing because it doesn't have to and probably doesn't want to care about it since the (libblockdev's) LVM API is the same independently on the plugin being used (that's the point, right?).

AFAICT, there are two ways to implement the above behaviour:

  1. Making libblockdev go through all the available so-names matching some pattern and choose from them the best one to load, then the second best etc.

    See the problems here? We would need to define some pattern for the plugins and some ordering conventions which would create quite a lot of noise in the /usr/lib64/ directory which is a mess even without it. Also, producing a list of such usable so-names from that directory is not entirely easy due to various symlinks and other mess that lives there.

  2. Make libblockdev configurable with so-names being part (the only, maybe?) of such configuration. That would allow packages with plugins alter the configuration making their so-names preferred over the default (or other) ones.

    What I see as the easiest and most practical solution for such configuration is to have the /etc/libblockdev/config.d directory with files like 00-default.cfg, 10-lvm-dbus.cfg, etc. that would be what GLib calls Key-value files -- basically .ini files or more precisely the format the .desktop files use. Every plugin would be a section/group and the only supported key right now would be soname. So the 00-default.cfg file would look like this:

    [btrfs]
    soname=libbd_btrfs.so.1
    
    [crypto]
    soname=libbd_crypto.so.1
    
    ...
    
    [lvm]
    soname=libbd_lvm.so.1
    
    ...

    The config files will be processed in the ascending order with soname's being pushed to stacks later used as priority lists of sonames when loading plugins with fallback. So if the 10-lvm-dbus.cfg file like this:

    [lvm]
    soname=libbd_lvm-dbus.so.1

    exists in the /etc/libblockdev/config.d/ directory, the result would be the libbd_lvm-dbus.so.1 file will be attempted to be loaded first falling back to libbd_lvm.so.1 if it fais. And of course the 10-lvm-dbus.cfg file would be shipped by the libblockdev-lvm-dbus package.

    Such config files can be processed with GLib's g_key_file_*() functions so it's really easy.

Any other options, suggestions or comments? I hope the option 2) looks better to everybody so unless somebody has a great and ultimate option 3) or unless somebody reveals a significant glitch in the option 2), I'm going to do the implementation of it.

Thanks!

@isimluk
Copy link

isimluk commented Oct 6, 2015

It really doesn't get any better than option 2. Even though it feels over-engineered, I cannot think of any better solution.

Applying KISS principle, I would perhaps try to load a single one and let the rpm packages conflict with each other (preferring simplicity and throwing flexibility under the bandwagon). However, I am not sure about reasons to use both on a single system.

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