Do I understand btrfs compression correctly?

Since we are referring to a one-time event to compress the data, there is little reason not to apply to an SSD. The lifespan of most SSDs won’t be materially impacted by that. Especially since the compression won’t be applied to files where the compression wouldn’t yield results which will include most larger files that are likely to be found on a desktop.

1 Like

You could view the BTRFS filesystem as an hard disk with a partition table, where the root filesystem is the primary partition and sub-volumes are the extra partitions.

The BTRFS filesystem allows you to access all directory tables in all partitions without the need to mount the partitions separately, except for the primary partition which you mount at the time you mount the BTRFS filesystem.

Because of this you are able to access every directory and file in the whole BTRFS filesytem while the needed info of some directories and files are kept in a different table (partition) transparent to the user.

Thank you all for your valuable input.

The current status is, I still use systemd-homed and when it detects that the /home partition is btrfs, it will automatically create a subvolume (for each user, I only have one) and mount the directory /home/username.homedir into /home/username.
This is a directory mount, systemd-homed could also mount a luks or differently encrypted image file which makes more sense than a folder mount.

So, it create a ephemeral mount home-username.mount which does exactly this.
It also shows up in /proc/mounts:

grep home /proc/mounts

/dev/mapper/crypthome /home btrfs rw,noatime,compress=zstd:3,ssd,discard=async,space_cache=v2,subvolid=5,subvol=/ 0 0
/dev/mapper/crypthome /home/username btrfs rw,nosuid,nodev,noatime,idmapped,compress=zstd:3,ssd,discard=async,space_cache=v2,subvolid=5,subvol=/ 0 0

The options in the first row are set by me, the second ones by systemd. There is no home-username.mount file anywhere. I can only see the specifics with systemctl show home-username.mount.

Then, the mystery begins.

We have output:

sudo btrfs subvolume show /home
/
	Name: 			<FS_TREE>
	UUID: 			00487190-dd99-4034-b8c2-01170924c98e
	Parent UUID: 		-
	Received UUID: 		-
	Creation time: 		2023-03-03 13:23:50 +0100
	Subvolume ID: 		5
	Generation: 		935
	Gen at creation: 	0
	Parent ID: 		0
	Top level ID: 		0
	Flags: 			-
	Send transid: 		0
	Send time: 		2023-03-03 13:23:50 +0100
	Receive transid: 	0
	Receive time: 		-
	Snapshot(s):

But for the user’s supposed subvolume:

$ sudo btrfs subvolume show /home/username
ERROR: Not a Btrfs subvolume: Invalid argument

However, the subvolume for the archived projects from a few posts before is there:

$ sudo btrfs subvolume show /home/username/archives
username.homedir/archives
	Name:            archives
	UUID:            444be83c-5670-0e41-84f1-c91f2d25e4f8
	Parent UUID:     -
	Received UUID:   -
	Creation time: 	2023-03-03 21:01:41 +0100
	Subvolume ID: 	256
	Generation: 		901
	Gen at creation: 	877
	Parent ID: 		5
	Top level ID: 	5
	Flags: 			-
	Send transid: 	0
	Send time: 		2023-03-03 21:01:41 +0100
	Receive transid: 	0
	Receive time:     -
	Snapshot(s):

But I can’t find any information about the mount info, it’s not a systemd-unit or in /proc/mounts.

As opposed to the discussion above, I think I was able to set the compression level of this subvolume with
$ sudo btrfs property set /home/username/archives compression zstd:9
Which I can verify with:

$ sudo btrfs property get /home/username/archives compression
compression=zstd:9

However, I don’t know if this is overridden by the parent mount or an invalid option.

I did some tests and a 100MB file from here and compressed it with the levels 1, 3, 8, 12, and 19 on a tmpfs:

100.000.000 100M
 40.678.709 100M-L1.zst
 37.372.605 100M-L2.zst
 35.487.160 100M-L3.zst
 31.607.256 100M-L8.zst
 30.413.324 100M-L12.zst
 26.954.633 100M-L19.zst

And to check on btrfs, I copied the file to the /home/username/archives subvolume and run compsize:

Processed 1 file, 763 regular extents (763 refs), 0 inline.
Type       Perc     Disk Usage   Uncompressed Referenced  
TOTAL       39%     39960576     100003840    100003840   
zstd        39%     39960576     100003840    100003840   

From what I see, it’s closest to compression level 1 when looking closely on the bytes.

So, it is smaller than level 1 but larger than level 2. Shouldn’t it be closer to level 3 if we can cut some slack on overhead? But the property that I’ve set above with using level 9 is surely not applied.

Try this instead:

systemctl status /home/username

It should show you how systemd mounted it, to see the actual config you could use cat instead of status.

$ sudo systemctl status /home/username                                              
● home-username.mount - /home/username
     Loaded: loaded (/proc/self/mountinfo)
     Active: active (mounted) since Mon 2023-03-06 09:17:41 CET; 3h 45min ago
      Where: /home/username
       What: /dev/mapper/crypthome

For cat: No files found for home-username.mount.

The info is there with

systemctl show /home/username
Where=/home/username
What=/dev/mapper/crypthome
Options=rw,nosuid,nodev,noatime,idmapped,compress=zstd:3,ssd,discard=async,space_cache=v2,subvolid=5,subvol=/
Type=btrfs
TimeoutUSec=1min 30s
ControlPID=0
DirectoryMode=0755
SloppyOptions=no
LazyUnmount=no
ForceUnmount=no
ReadWriteOnly=no
Result=success
UID=[not set]
GID=[not set]
Slice=system.slice
[...]
Id=home-username.mount
Names=home-username.mount
Requires=dev-mapper-crypthome.device home.mount -.mount system.slice
Conflicts=umount.target
Before=local-fs.target session-2.scope umount.target
After=local-fs-pre.target systemd-journald.socket blockdev@dev-mapper-crypthome.target system.slice home.mount -.mount dev-mapper-crypthome.device
RequiresMountsFor=/home
Description=/home/username
LoadState=loaded
ActiveState=active
FreezerState=running
SubState=mounted
SourcePath=/proc/self/mountinfo
StateChangeTimestamp=Mon 2023-03-06 09:17:41 CET
StateChangeTimestampMonotonic=67906042
InactiveExitTimestamp=Mon 2023-03-06 09:17:41 CET
InactiveExitTimestampMonotonic=67906042
ActiveEnterTimestamp=Mon 2023-03-06 09:17:41 CET
ActiveEnterTimestampMonotonic=67906042
ActiveExitTimestampMonotonic=0
InactiveEnterTimestampMonotonic=0
CanStart=yes
CanStop=yes
CanReload=yes
CanIsolate=no
CanFreeze=no
StopWhenUnneeded=no
RefuseManualStart=no
RefuseManualStop=no
AllowIsolate=no
DefaultDependencies=yes
OnSuccessJobMode=fail
OnFailureJobMode=replace
IgnoreOnIsolate=yes
NeedDaemonReload=no
JobTimeoutUSec=infinity
JobRunningTimeoutUSec=infinity
JobTimeoutAction=none
ConditionResult=no
AssertResult=no
ConditionTimestampMonotonic=0
AssertTimestampMonotonic=0
Transient=no
Perpetual=no
StartLimitIntervalUSec=10s
StartLimitBurst=5
StartLimitAction=none
FailureAction=none
SuccessAction=none
InvocationID=d890471d826e44e9a6b04b394223e61f
CollectMode=inactive

But this doesn’t show any btrfs information. It could be anything (luks volume, ecryptfs or whatever else systemd supports.).

Please be aware, that btrfs will NOT compress a file as one block of data, but will break it up in several small chunks. This may affect compression ratio. This is visible if you look onto fragmentation of a compressed file.

Level 3 is very good. I use Level 9 overall and have better then 2:1 over all files.

Sure, thanks, I’ll plan on using something between 8 and 12, however, currently I don’t even know if it’s using compression and of so, which level and where it’s configured.
The test would indicate that it’s using the default level 3.

There is no way to set this or even check which one is used.

mount |grep -E btrfs
/dev/sda2 on / type btrfs (rw,noatime,compress=zstd:9,ssd,space_cache,commit=300,subvolid=36033,subvol=/@

Read the docs of the developers It is what it says :wink:

1 Like

But the subvolume is not mounted by me or ay unit I can find. It seems it’s transient (?). It’s not listed in the mounts.

The sentence is confusing, the compression level can be set during mounting the subvolume but is shared. So which one is it?

Edit:
Okay, so the subvolume can’t be mounted by name, however, with subvolid it can be mounted:

sudo mount -o subvolid=256,compression=zstd:9,noatime /dev/mapper/crypthome archives

but the compression level is not applied:

$ grep archives /proc/self/mounts
/dev/mapper/crypthome /home/username.homedir/archives btrfs rw,noatime,compress=zstd:3,ssd,discard=async,space_cache=v2,subvolid=256,subvol=/username.homedir/archives 0 0

:disappointed_relieved:

So, I can understand the docs: the compression level can be set during mount (can as it can be set without failing), however, it is then overwritten by the parent volume (what they weirdly call shared.)

I only found a few posts from 10-12 years ago complaining about this, but they all end in a “they are working on it” and “it works now” (the latter is probably falling for the same logic that it doesn’t error out when setting the level) and the first one is from their wiki

Can I set compression per-subvolume?
Currently no, this is planned. You can simulate this by enabling compression on the subvolume directory and the files/directories will inherit the compression flag.

So, @andreas85’s idea of differently compressed subvolumes doesn’t work.

1 Like

So bear with me here, I have an idea.

I have mounted /home in fstab and a mysterious subvolume to /home/username and then my archived subvolume. So far so good.

From a few experiments, I would very much have the archive subvolume at zstd:12. I almost never write to it (once every few months, I can wait for the copy, no problem) and reading doesn’t need to be realtime.

As the root volume ( here /home) is mounted with zstd:3, couldn’t I “just” for copying files to the archive remount the full volume? In TTY, this should be relatively easy, right?

# On TTY1
sudo umount /home
sudo mount -o defaults,noatime,compress=zstd:12 /dev/mapper/crypthome /home
# On TTY2
rsync -av --info=progress2 /home/username/project/a /home/username/archive/
logout
# On TTY1
sudo umount /home
sudo mount -a

Or am I totall out of place?

I’m not sure if you are able to unmount /home while loged into a normal user (non-root) in the GUI, because of some files keeping that mount bussy.

You could try it on the console yea maybe…

did i say something funny? :joy: :woman_shrugging:
ahhh TTY = console right? :woman_facepalming:

Today, I checked systemd-homed in VM.

I noticed that systemd-homed creates a new separate filesystem for a new user, that means each homed-user has its own file system that is independent of other file system on home partition.

fstab is useless for systemd-homed. But systemd-homed has nice configuration:

Check homectl --help to show the mount option: --luks-extra-mount-options

sudo homectl update [USER_NAME] --luks-extra-mount-options=‘compress=zstd:9’

$ systemctl show home-user.mount 
Where=/home/user
What=/dev/mapper/home-user
Options=rw,nosuid,nodev,relatime,idmapped,compress=zstd:9,ssd,noacl,space_cache=v2,subvolid=256,subvol=/user

It shows zstd:9. That works!

2 Likes

Is that called uhm…“Filesystem namespace” or something?
Like a virtual network but this time a virtual filesystem…

Not completely related to what i wrote above but still nice to link in this topic:

AFAIK, the native filesystem is stored in user.home as a file.

There is my clear proof in VM to show: :point_down:
Why I have two Btrfs filesystems:

$ sudo btrfs filesystem show
Label: 'System'  uuid: 8b945945-d355-4de3-9c51-820a66b79dc2
        Total devices 1 FS bytes used 24.52GiB
        devid    1 size 27.95GiB used 27.95GiB path /dev/sda2

Label: 'user'  uuid: d0f5beb9-f237-4596-842a-93ad894684f2
        Total devices 1 FS bytes used 32.90MiB
        devid    1 size 13.90GiB used 1.52GiB path /dev/mapper/home-user

One for the system partition, others for homed-user.

Yes systemd-homed does that indeed, as far as i could read the docs for it.
But i meant the way it is mounted, is not like a regular mount, but instead a containerized mount using namespaces…
I can’t at moment find the info referring to that otherwise i would have linked to that.
Anyway what i understood back then is that it works similar to PrivateTemp etc with respect to access to other processes…

I could be totaly fried again at this hour, so in that case just ignore my late night blabler as usual :joy:

The behavior of user.home as systemd-homed file is similar to Veracrypt , that is just logic. :wink:


Systemd-Homed would be a bit cumbersome because filesystems run on top of other filesystem. Of course, performance will be reduced and lower stability.

I like to use LUKS partition instead of systemd-homed.

See the UUID: 773f91ef-66d4-49b5-bd83-d683bf40ad16 in:

Which makes me believe you are able to use partitions also instead of a file mounted via a loopback device…
Escpecially when using Luks…

Thank you for investigating. In my case, I don’t have a separate filesystem because I don’t use LUKS with systemd-homed.

From my post above, I’ve done exactly this:

  1. Logged out (systemd unmounts /home/username)
  2. Switch to TTYx and log in as root (no /home needed)
  3. Umount /home
  4. Mount /home with additional option compress=zstd:12
  5. Switch to TTYy and log in as username (systemd now mounts /home/username)
  6. The compression option is inherited: compress=zstd:12 is listed in /proc/mounts
  7. Move all directories/files from their old location to the /home/username/archives subvolume
  8. Log out
  9. Switch back to TTYx, unmount /home, mount -a
  10. Log in graphical environment: Done.

I can see with compsize that the /home/username/archives directory takes less disk space and has a higher zstd column than the old locations with zstd:3.

To maintain level 12, I’ve set the subvolume to read-only (btrfs property set . ro true), which, obviously, must be reset prior to writing above.

A job well done! Thank you all for participating, it wouldn’t have been possible without you.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.