Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: btrfs plugin: use libbtrfsutil #999

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

jelly
Copy link
Contributor

@jelly jelly commented Jan 22, 2024

This is a quick hack to start off the discussion if libbtrfsutil would be a good fit for extending further features in the btrfs plugin for libblockdev. ( I recall there was a discussion somewhere, but couldn't find the issue)

Some notable things which needs to be verified:

  • License, libbtrfsutil itself is licensed LGPL, is it compatible with libblockdev?
  • Feature completeness, can everything currently be replaced with libbtrfsutil and what is missing, can it be supported in libbtrfsutil and is upstream willing too?
  • Is libbtrfsutil packaged everywhere libblockdev is at the moment used.

Important note:

libbtrfsutil only includes operations that are done through the filesystem and ioctl interface, not operations that modify the filesystem directly (e.g., mkfs or fsck). This is by design but also a legal necessity, as the filesystem implementation is GPL but libbtrfsutil is LGPL. That is also why the libbtrfsutil code is a reimplementation of the btrfs-progs code rather than a refactoring. Be wary of this when porting functionality.


Porting todo

  • btrfs default subvolume get/set
  • listing subvolumes
  • create subvolume
  • delete subvolume

Missing

  • volume information (bd_btrfs_filesystem_info) (ideally also RAID/ multi device information which is now lacking (btrfs device usage /))
  • device add/remove support
  • set label?
  • bd_list_devices
  • create volume

@StorageGhoul
Copy link

Can one of the admins verify this patch?

@vojtechtrefny
Copy link
Member

This is a quick hack to start off the discussion if libbtrfsutil would be a good fit for extending further features in the btrfs plugin for libblockdev.

Definitely something we'd like to do. Every command call we can replace with a library call is a huge improvement.

( I recall there was a discussion somewhere, but couldn't find the issue)

That would be #552

Some notable things which needs to be verified:

* [ ]  License, libbtrfsutil itself is licensed LGPL, is it compatible with libblockdev?

Yes, libblockdev is also licensed under LGPL 2.1 so there shouldn't be a problem.

* [ ]  Feature completeness, can everything currently be replaced with libbtrfsutil and what is missing, can it be supported in libbtrfsutil and is upstream willing too?

It would be great if we could replace everything with libbtrfsutil, but I am ok with replacing only parts of the command calls with the library.

* [ ]  Is libbtrfsutil packaged everywhere libblockdev is at the moment used.

Libblockdev is packaged pretty much everywhere these days, but libbtrfsutil seems to be available in both Fedora and Debian/Ubuntu and that's good enough at least for our CI :)

@@ -229,6 +229,10 @@ AS_IF([test "x$with_fs" != "xno" -o "x$with_crypto" != "xno" -o "x$with_swap" !=
[Define as neutral value if libblkid doesn't provide the definition])])]
[])

AS_IF([test "x$with_btrfs" != "xno"],
[LIBBLOCKDEV_PKG_CHECK_MODULES([LIBBTRFSUTIL], [libbtrfsutil >= 6.6])],
[])
Copy link
Member

Choose a reason for hiding this comment

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

To unblock some of the CI, you'll need to libbtrfsutil dependency to few places:

  • dist/libblockdev.spec.in
  • misc/install-test-dependencies.yml
  • .packit.yaml

This will cover Packit and the GH actions checks (we'll also need to add it to our internal CI, but that's something we need to do manually).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, applied it.

@jelly
Copy link
Contributor Author

jelly commented Jan 22, 2024

This is a quick hack to start off the discussion if libbtrfsutil would be a good fit for extending further features in the btrfs plugin for libblockdev.

Definitely something we'd like to do. Every command call we can replace with a library call is a huge improvement.

( I recall there was a discussion somewhere, but couldn't find the issue)

That would be #552

Some notable things which needs to be verified:

* [ ]  License, libbtrfsutil itself is licensed LGPL, is it compatible with libblockdev?

Yes, libblockdev is also licensed under LGPL 2.1 so there shouldn't be a problem.

Nice!

* [ ]  Feature completeness, can everything currently be replaced with libbtrfsutil and what is missing, can it be supported in libbtrfsutil and is upstream willing too?

It would be great if we could replace everything with libbtrfsutil, but I am ok with replacing only parts of the command calls with the library.

So from the LGPL/GPL note in the documentation, I can make up that it is basically everything mkfs, repair and possibly btrfs device add.

* [ ]  Is libbtrfsutil packaged everywhere libblockdev is at the moment used.

Libblockdev is packaged pretty much everywhere these days, but libbtrfsutil seems to be available in both Fedora and Debian/Ubuntu and that's good enough at least for our CI :)

It's also available in Arch Linux. I should add the required CI changes, for Fedora this would mean a dependency on libbtrfsutil which btrfs-progs does not depend on (due to the licensing afaik).

Copy link
Member

@tbzatek tbzatek left a comment

Choose a reason for hiding this comment

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

Very nice!

g_match_info_free (match_info);
g_regex_unref (regex);
g_free (output);
err = btrfs_util_get_default_subvolume(mountpoint, &ret);
Copy link
Member

Choose a reason for hiding this comment

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

Minor nitpick: please use Gnome-like codestyle, i.e. a space before opening parenthesis.

g_free (output);
err = btrfs_util_get_default_subvolume(mountpoint, &ret);
if (err)
g_set_error (error, BD_BTRFS_ERROR, BD_BTRFS_ERROR_PARSE, btrfs_util_strerror(err));
Copy link
Member

Choose a reason for hiding this comment

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

I think we can afford changing error codes a little bit, if needed. While it would be nice to keep most of them consistent, I imagine the code path would be so different anyway and it would be good to distinguish between minor errors (i.e. "device open error", "parse error", "invalid argument", etc.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, currently the error is rather strange when given a path which is not mounted. So this needs more work.

AssertionError: ".*(can't|cannot) access.*" does not match "g-bd-btrfs-error-quark: Could not open (2)" 

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a C style API so the test of the error was in errno.

Copy link
Member

Choose a reason for hiding this comment

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

Different error messages are fine, there's generally no guarantee of stability and clients should never match any strings (it's okay for tests where it is intentional) - that's what the error codes are for.

@jelly jelly force-pushed the libbtrfsutil branch 2 times, most recently from d9b9b8f to 65eac48 Compare January 22, 2024 20:27
@@ -229,6 +229,10 @@ AS_IF([test "x$with_fs" != "xno" -o "x$with_crypto" != "xno" -o "x$with_swap" !=
[Define as neutral value if libblkid doesn't provide the definition])])]
[])

AS_IF([test "x$with_btrfs" != "xno"],
[LIBBLOCKDEV_PKG_CHECK_MODULES([LIBBTRFSUTIL], [libbtrfsutil >= 5.1])],
Copy link
Contributor Author

@jelly jelly Jan 22, 2024

Choose a reason for hiding this comment

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

This is a bit arbitrary, needs some investigation which version is really needed, then again 5.1 is from 2019.

* @error: (out) (optional): place to store error (if any)
*
* Returns: whether the @mountpoint volume's default subvolume was correctly set
* to @subvol_id or not
*
* Tech category: %BD_BTRFS_TECH_SUBVOL-%BD_BTRFS_TECH_MODE_MODIFY
*/
gboolean bd_btrfs_set_default_subvolume (const gchar *mountpoint, guint64 subvol_id, const BDExtraArg **extra, GError **error) {
const gchar *argv[6] = {"btrfs", "subvol", "set-default", NULL, mountpoint, NULL};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This breaks udisks, which I think we rather not? But -Werror will scream at me if I keep it around. I guess I should mark it with something __unused?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, existing public API cannot be changed. Please add G_GNUC_UNUSED annotation.

If you want to keep full API compatibility, you'd need to translate any known extra args to library calls/arguments. Porting existing API is tough, creating new API from scratch is much easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think deprecating the argument would be the best, I am not sure what extra options can be given as btrfs subvolume set default only takes:

btrfs subvolume set-default <subvolid> <path>

So I think for backwards compatibility this would actually work out quite well in this instance. Should I add G_DEPRECATED as well to the argument and update the comment?

Copy link
Member

Choose a reason for hiding this comment

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

No need to special annotation for function arguments I guess.

libblockdev has historically used btrfs-progs CLI utilities in the
meanwhile libbtrfsutil has been developed and used by snapper.

Not parsing CLI output and using the library functions should provide a
more stable way to gather information from btrfs.
libbtrfsutil provides it's own error enum for libbtrfsutil functions and
as we no longer parse output this introduces a BD_BTRFS_ERROR_NOT_FOUND
error type. As the mount point not being found is the most likely
failure scenario.
@jelly jelly force-pushed the libbtrfsutil branch 2 times, most recently from a81a7a7 to 4108205 Compare March 5, 2024 13:30
Use libbtrfsutil's subvolume iterator to obtain a list of subvolumes in
order. In the future this would allow exposing more information about a
subvolume to list_subvolumes.
Avoids having to exec btrfs-progs and allows us to implement recursive
subvolume deletion in the future.
@jelly
Copy link
Contributor Author

jelly commented Mar 6, 2024

I've rebased and ported all functions which can use libbtrfsutil. I haven't managed to land a new feature yet in libbtrfsutil. But I don't think btrfs-progs wants to block new additions to the API.

This is all still a bit WiP, there are some TODO's regarding error checking and one test which cannot be ported as it overrides btrfs subvolume list (The weird docker subvolumes one). But in all it seems to shave off ~ 100 loc.

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.

4 participants