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

btrfs-progs: mkfs: add --compression #882

Merged
merged 4 commits into from
Nov 5, 2024

Conversation

maharmstone
Copy link
Contributor

Adds a --compression option to mkfs.btrfs when using --rootdir.

Copy link
Collaborator

@adam900710 adam900710 left a comment

Choose a reason for hiding this comment

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

Just some small code style nitpicks.

mkfs/rootdir.c Outdated Show resolved Hide resolved
mkfs/rootdir.c Outdated Show resolved Hide resolved
mkfs/rootdir.c Outdated Show resolved Hide resolved
mkfs/rootdir.c Outdated Show resolved Hide resolved
@maharmstone
Copy link
Contributor Author

Thanks Qu

convert/source-ext2.c Outdated Show resolved Hide resolved
@@ -489,7 +490,8 @@ static int ext2_create_symlink(struct btrfs_trans_handle *trans,
pathname = (char *)&(ext2_inode->i_block[0]);
BUG_ON(pathname[inode_size] != 0);
ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
pathname, inode_size + 1);
pathname, inode_size + 1,
0, inode_size + 1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

inode_size + 1 is here because I've added a separate ram_bytes param to btrfs_insert_inline_extent, because it's no longer necessarily the same as size.

Copy link
Collaborator

@adam900710 adam900710 Sep 3, 2024

Choose a reason for hiding this comment

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

In fact this is a minor problem in the existing convert code. The resulted symlink would be one byte larger than the original path (but inode size is still correct).

E.g.
The original ext4 has a link to file name path:

lrwxrwxrwx 1 root root 4 Sep  3 10:27 path -> path

But after convert, the result looks like this:

	item 10 key (267 INODE_ITEM 0) itemoff 15543 itemsize 160
		generation 1 transid 1 size 4 nbytes 5
		block group 0 mode 120777 links 1 uid 0 gid 0 rdev 0
		sequence 0 flags 0x0(none)
		atime 1725325025.930020384 (2024-09-03 10:27:05)
		ctime 1725325023.110085974 (2024-09-03 10:27:03)
		mtime 1725325023.110085974 (2024-09-03 10:27:03)
		otime 1725325023.110085974 (2024-09-03 10:27:03)
	item 11 key (267 INODE_REF 256) itemoff 15529 itemsize 14
		index 3 namelen 4 name: path
	item 12 key (267 EXTENT_DATA 0) itemoff 15503 itemsize 26
		generation 4 type 0 (inline)
		inline extent data size 5 ram_bytes 5 compression 0 (none)

Note the link has one extra byte.

It's definitely not your fault nor it's causing problems, but I guess I'll fix it before your patchset.

Copy link
Collaborator

@adam900710 adam900710 Sep 3, 2024

Choose a reason for hiding this comment

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

And the fix for that is here: #884

Since our current plan is to merge subvolume related feature in v6.11 first then compression for v6.12, so we should have plenty time to get the fix merged then this refactor.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The proper fix for that bug is here: #885

In fact the +1 is already causing btrfs/012 random failures.
So that has to be fixed anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I'll rebase once you've committed your fixes.

@@ -538,7 +539,7 @@ static int reiserfs_copy_symlink(struct btrfs_trans_handle *trans,
len = get_ih_item_len(tp_item_head(&path));

ret = btrfs_insert_inline_extent(trans, root, objectid, 0,
symlink, len + 1);
symlink, len + 1, 0, len + 1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As in ext2_create_symlink

Copy link
Collaborator

Choose a reason for hiding this comment

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

The same bug as ext2_create_symlink

mkfs/main.c Outdated Show resolved Hide resolved
mkfs/rootdir.c Outdated Show resolved Hide resolved
mkfs/rootdir.c Outdated Show resolved Hide resolved
mkfs/rootdir.c Show resolved Hide resolved
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Aug 30, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Aug 30, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Aug 31, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Aug 31, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Aug 31, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 1, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 1, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 1, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 1, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 2, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
@maharmstone
Copy link
Contributor Author

Pushed new version with changes discussed.

@adam900710 adam900710 added this to the v6.12 milestone Sep 3, 2024
Copy link
Collaborator

@adam900710 adam900710 left a comment

Choose a reason for hiding this comment

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

Just a really small nitpick. Otherwise the first patch looks perfect to me.

mkfs/rootdir.c Outdated Show resolved Hide resolved
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 3, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 3, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.
DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 3, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.

We don't add support for btrfs just yet until the corresponding PR
in btrfs-progs is merged.
@DaanDeMeyer
Copy link

@adam900710 Any chance this could be considered for 6.11 as well? Then we can land support for this in systemd-repart in the upcoming systemd 257 release.

DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 3, 2024
Now that mkfs.btrfs is adding support for compressing the generated
filesystem (kdave/btrfs-progs#882), let's
add general support for specifying the compression algorithm and
compression level to use.

We opt to not parse the specified compression algorithm and instead
pass it on as is to the mkfs tool. This has a few benefits:

- We support every compression algorithm supported by every tool
  automatically.
- Users don't need to modify systemd-repart if a mkfs tool learns a
  new compression algorithm in the future
- We don't need to maintain a bunch of tables for filesystem to map
  from our generic compression algorithm enum to the filesystem specific
  names.

We don't add support for btrfs just yet until the corresponding PR
in btrfs-progs is merged.
@adam900710
Copy link
Collaborator

David is not hurry to push so many features in one single release.

And considering this is only for compression, it shouldn't cause too much change except the image size.

DaanDeMeyer added a commit to DaanDeMeyer/systemd that referenced this pull request Sep 3, 2024
@DaanDeMeyer
Copy link

David is not hurry to push so many features in one single release.

And considering this is only for compression, it shouldn't cause too much change except the image size.

The image size is roughly halved by enabling this in my case, which can make a huge difference.

@adam900710
Copy link
Collaborator

adam900710 commented Sep 3, 2024

Compression is indeed awesome to reduce the image size, but here we really want to go a more stable methods towards new features.

In fact, thanks to the recent refactor (the first patch of the series) from @maharmstone , we have already pinned down a btrfs-convert bug that may lead to invalid soft link.
So I want to be a little more cautious here.

@kdave may give a better roadmap on this, and do the final call.

@maharmstone maharmstone force-pushed the compression branch 2 times, most recently from ac86e57 to 802c51b Compare September 3, 2024 10:18
@maharmstone
Copy link
Contributor Author

Pushed with latest change

@adam900710 adam900710 added enhancement mkfs Changes in mkfs.btrfs labels Sep 4, 2024
@Conan-Kudo
Copy link
Contributor

It would be really great for us image build tools if this landed in 6.11 / systemd 257. It becomes possible to create Fedora images mostly offline and unprivileged with these features.

Documentation/mkfs.btrfs.rst Outdated Show resolved Hide resolved
@maharmstone maharmstone force-pushed the compression branch 2 times, most recently from 34f2cab to 6f29be7 Compare September 6, 2024 16:24
@maharmstone
Copy link
Contributor Author

I've pushed a new version, which includes setting the level and renaming --compression to --compress. I've changed it so that the base patch includes zlib and the subsequent patch adds zstd, on the grounds that zlib is a hard dependency but zstd isn't.

@maharmstone
Copy link
Contributor Author

Rebased against devel

@maharmstone
Copy link
Contributor Author

I've added LZO too, to round it off

@kdave kdave force-pushed the devel branch 2 times, most recently from f6d1943 to 5ff9f62 Compare September 17, 2024 15:00
There were two major problems with the function add_file_items: it was
writing all files sector-by-sector, making compression impossible, and
it was assuming that pread would never do a short read.

Fix these problems, and create a new helper function read_and_write_extent.

Signed-off-by: Mark Harmstone <[email protected]>
Adds an option --compress to mkfs.btrfs, to allow creating files
using zlib when using --rootdir.

Signed-off-by: Mark Harmstone <[email protected]>
Allows --compress to work with zstd, when compiled in.

Signed-off-by: Mark Harmstone <[email protected]>
Allows --compress to work with lzo.

Signed-off-by: Mark Harmstone <[email protected]>
@maharmstone
Copy link
Contributor Author

Pushed rebase

Copy link
Collaborator

@adam900710 adam900710 left a comment

Choose a reason for hiding this comment

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

Sorry I merged the branch by incident, and I can not find a way to re-open the merge request.

It turns out that when modifying the code inside my editor, it's much easier to expose problems, than viewing it through github web.
(Not to mention github hides large chunks of code by default).


ret_read = pread(fd, buf + bytes_read, to_read - bytes_read,
file_pos + bytes_read);
if (ret_read == -1) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use ret_read < 0, as that's the common practice for detecting an error, not only for the common IO but also all the other btrfs specific calls.

*/
#define MAX_EXTENT_SIZE SZ_1M

static int read_and_write_extent(struct btrfs_trans_handle *trans,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I found the function name read_and_write_extent() a little hard to grasp.

The caller is add_file_items(), what about just a simple add_one_file_item().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because it's not adding a file item, it's adding an extent.

I'll rename it to add_file_item_extent.

static int read_and_write_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_inode_item *btrfs_inode,
u64 objectid, int fd, u64 file_pos, char *buf,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Everything from fd, buf, size (from st structure), and path_name is only here to help read the file.
The only thing changing is file_pos which is worth a dedicated parameter.

During my initial failed merge, I added an extra helper structure, source_descriptor, to include fd, st, path and buf. Later expands the structure to add compressed_buf for compression.

Such structure is more expandable than adding more and more parameters to the already long list.

error("cannot read %s at offset %llu length %llu: %m",
path_name, bytes_read, (unsigned long long)st->st_size);
error("cannot read %s at offset %u length %llu: %m",
path_name, 0, (unsigned long long)st->st_size);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since you are here, you can also fix the length output, without using a forced (unsigned long long) conversion, but %zu.

@@ -212,6 +212,15 @@ OPTIONS

$ mkfs.btrfs -O list-all

--compress <algo>:<level>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since level is optional, please use --compress <algo>[:<level>] instead.

@@ -285,3 +285,93 @@ int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
}
return ret;
}

int btrfs_record_file_extent_comp(struct btrfs_trans_handle *trans,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please do no use comp as a short name for compress, it's a little confusing.

But it will no longer be a problem if we address the next comment.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It turns out that we should not use btrfs_record_file_extent() except for convert.

The extra handling inside btrfs_record_file_extent() is specially designed for convert, where we may have an existing data extent from the convert image, thus it is not a good way to support compressed data extents.

For mkfs cases, I'll craft a dedicated help for it with a more expandable interface during my cleanup.

struct btrfs_inode_item *inode,
u64 file_pos, u64 disk_bytenr,
u64 extent_num_bytes, u64 ram_bytes,
enum btrfs_compression_type comp)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of the longer and longer parameter list, what about something just like btrfs_ordered_extent inside the kernel, to record all the needed info?

So that we do not need two different btrfs_record_file_extent(), but a single one to handle them all, just like kernel.

This will need a dedicated cleanup patch first, to introduce some structure like btrfs_ordered_extent.

mkfs/main.c Outdated
@@ -443,6 +443,7 @@ static const char * const mkfs_usage[] = {
OPTLINE("-u|--subvol TYPE:SUBDIR", "create SUBDIR as subvolume rather than normal directory, can be specified multiple times"),
OPTLINE("--shrink", "(with --rootdir) shrink the filled filesystem to minimal size"),
OPTLINE("-K|--nodiscard", "do not perform whole device TRIM"),
OPTLINE("--compress ALGO:LEVEL", "compression algorithm and level to use; ALGO can be no (default), zlib"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also [] for the level.

u64 flags;

flags = btrfs_stack_inode_flags(btrfs_inode);
flags |= BTRFS_INODE_NOCOMPRESS;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I prefer not to pass a btrfs inode and handle its flags inside a compression function.

Such compression function should only do the compression. And let the caller handling the btrfs specific things.
(E.g. if the compressed size is larger than the input, return -E2BIG to inform the caller just like what kernel does).

break;
}

if (ret == 1) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please do not use immediate number other than 0, so this should be if (ret > 0) {

@adam900710
Copy link
Collaborator

BTW, I have submitted the series cleaning up the file extent insertion code:
#919

Now for mkfs rootdir usage, we should go the new helper, insert_reserved_file_extent(), and it accepts an on-stack file extent item pointer, so caller can specify all the members, just like what we did inside the kernel.

This should allow the function to be utilized by both regular and compressed file extents, again, just like the kernel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement mkfs Changes in mkfs.btrfs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants