borgmatic not parsing all included source_directories when using btrfs #1192

Closed
opened 2025-11-27 18:32:07 +00:00 by fortellerq · 15 comments

What I'm trying to do and why

Hello!
I am not entirely sure if I am seeing a bug, or misconfiguration on my side. If anything, I think btrfs documentation could use some usage examples to help understand how to configure it properly.

What I have is up-to-date Nobara Linux system (Fedora 43) with borgmatic installed using packages from Fedora, so I have pretty recent version:

$ borgmatic --version
2.0.10

What I also have, is default btrfs partition layout. I want to backup root and /home partitions:

$ sudo btrfs subvolume list /
ID 256 gen 11419 top level 5 path @
ID 257 gen 11419 top level 5 path @home
ID 258 gen 9806 top level 5 path @swap
ID 277 gen 10681 top level 257 path @home/.borgmatic-snapshot-18546/home
ID 279 gen 11390 top level 256 path .borgmatic-snapshot-7335

However, unless I provide two separate configs /etc/borgmatic.d/{root,home}.yaml with exactly the same configs but different path, borgmatic always backups up only the root partition. The order in the configuration file doesn't matter - home can be first, root can be first - only root is processed. If /home is the only provided path, then /home is processed properly. When separate config files are provided in borgmatic.d folder, then both files are processed properly, but result is not exactly what I expect due to following reasons:

  1. Result is two separate backups
  2. Second snapshot is created only after the first backup is fully processed. What I would prefer to see is to create both snapshots at the same time to avoid data corruption / misalignment.

I do realize that I somewhat abuse borgmatic.d functionality as its main usecase is meant for separate repositories, but this workaround seems to be the only option I found thus far to get both root and /home backed up.

Thank you for this great tool. Documentation is actually outstanding and borgmatic has a lot of nice features! And I realize I might be missing something trivial here.

Steps to reproduce

source_directories:
    - /
    - /home
repositories:
    - path: <REMOVED_SSH_PATH>
exclude_patterns:
        - /dev
        - /proc
        - /sys
        - /run
        - /tmp
        - /var/tmp
        - /lost+found
        - /mnt
        - /media
encryption_passphrase: <REMOVED_PASSPHRASE>
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
checks:
     - name: repository
       frequency: 2 weeks
btrfs:

Actual behavior

$ sudo borgmatic create --verbosity 2 | tee borgmatic_combined.txt
/etc/borgmatic/config.yaml: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg --version --debug --show-rc
/etc/borgmatic/config.yaml: Borg 1.4.2
ssh://<REMOVED_SSH_PATH>: Running actions for repository
ssh://<REMOVED_SSH_PATH>: Creating archive
ssh://<REMOVED_SSH_PATH>: Using runtime directory /tmp/borgmatic-ppp86eb_/borgmatic
ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap
ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: btrfs subvolume show /
ssh://<REMOVED_SSH_PATH>: btrfs property get -t subvol / ro
ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume
ssh://<REMOVED_SSH_PATH>: Looking for snapshots to remove in /.borgmatic-snapshot-*
ssh://<REMOVED_SSH_PATH>: Deleting Btrfs snapshot /.borgmatic-snapshot-18546
ssh://<REMOVED_SSH_PATH>: btrfs subvolume delete /.borgmatic-snapshot-18546
Delete subvolume 278 (no-commit): '//.borgmatic-snapshot-18546'
ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps
ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function dump_data_sources
ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function dump_data_sources
ssh://<REMOVED_SSH_PATH>: Snapshotting Btrfs subvolumes
ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume
ssh://<REMOVED_SSH_PATH>: Creating Btrfs snapshot for / subvolume
ssh://<REMOVED_SSH_PATH>: btrfs subvolume snapshot -r / /.borgmatic-snapshot-7335
Create readonly snapshot of '/' in '/.borgmatic-snapshot-7335'
ssh://<REMOVED_SSH_PATH>: Writing patterns to /tmp/borgmatic-ppp86eb_/borgmatic/tmp9lbe9ck8:
! fm:/.borgmatic-snapshot-7335/.borgmatic-snapshot-7335
R /etc/borgmatic/config.yaml
+ /etc/borgmatic/config.yaml
R /tmp/borgmatic-ppp86eb_/./borgmatic/bootstrap
+ /tmp/borgmatic-ppp86eb_/./borgmatic/bootstrap
R /.borgmatic-snapshot-7335/./
+ /.borgmatic-snapshot-7335/./
! fm:/dev
! fm:/proc
! fm:/sys
! fm:/run
! fm:/tmp
! fm:/.borgmatic-snapshot-7335/./var/tmp
! fm:/.borgmatic-snapshot-7335/./lost+found
! fm:/.borgmatic-snapshot-7335/./mnt
! fm:/.borgmatic-snapshot-7335/./media
ssh://<REMOVED_SSH_PATH>: Checking file paths Borg plans to include
ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-ppp86eb_/borgmatic/tmp9lbe9ck8 ssh://<REMOVED_SSH_PATH>::{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f} --dry-run --list
ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-ppp86eb_/borgmatic/tmp9lbe9ck8 --debug --show-rc ssh://<REMOVED_SSH_PATH>::{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}
using builtin fallback logging configuration
33 self tests completed in 0.05 seconds
SSH command line: ['ssh', '-p', '1272', 'borg@<REMOVED_IP>', 'borg', 'serve', '--debug']
Remote: using builtin fallback logging configuration
Remote: 33 self tests completed in 0.06 seconds
Remote: using builtin fallback logging configuration
Remote: Initialized logging system for JSON-based protocol
Remote: Resolving repository path b'<REMOVED_PATH>borg'
Remote: Resolved repository path to '<REMOVED_PATH>borg'
Remote: Verified integrity of <REMOVED_PATH>borg/index.250
TAM-verified manifest
security: read previous location 'ssh://<REMOVED_SSH_PATH>'
security: read manifest timestamp '2025-11-27T00:20:10.278222'
security: determined newest manifest timestamp as 2025-11-27T00:20:10.278222
security: repository checks ok, allowing access
Creating archive at "ssh://<REMOVED_SSH_PATH>::PMR-NOBARA-2025-11-27T19:03:35.719220"
Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/chunks
Reading files cache ...
Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/files
security: read previous location 'ssh://<REMOVED_SSH_PATH>'
security: read manifest timestamp '2025-11-27T00:20:10.278222'
security: determined newest manifest timestamp as 2025-11-27T00:20:10.278222
security: repository checks ok, allowing access
Processing files ...
Remote: Cleaned up 0 uncommitted segment files (== everything after segment 250).
Remote: Verified integrity of <REMOVED_PATH>borg/hints.250
Remote: check_free_space: required bytes 666483458, free bytes 3618791550976
security: saving state for c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654 to /root/.config/borg/security/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654
security: current location   ssh://<REMOVED_SSH_PATH>
security: key type           5
security: manifest timestamp 2025-11-27T18:06:13.422235
RemoteRepository: 307.25 MB bytes sent, 5.85 kB bytes received, 228 messages sent
terminating with success status, rc 0
ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap
ssh://<REMOVED_SSH_PATH>: Removing bootstrap manifest at /tmp/borgmatic-ppp86eb_/borgmatic/bootstrap/manifest.json
ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps
ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps

summary:
/etc/borgmatic/config.yaml: Loading configuration file
/etc/borgmatic/config.yaml: Successfully ran configuration file

Expected behavior

I would expect to process both /home and root with given config file.

Other notes / implementation ideas

Nothing comes to mind :)

borgmatic version

2.0.10

borgmatic installation method

Fedora package

Borg version

1.4.2

Python version

Python 3.14.0

Database version (if applicable)

not applicable / no database being backed up

Operating system and version

Nobara Linux 43 (KDE Plasma Desktop Edition)

### What I'm trying to do and why Hello! I am not entirely sure if I am seeing a bug, or misconfiguration on my side. If anything, I think btrfs documentation could use some usage examples to help understand how to configure it properly. What I have is up-to-date Nobara Linux system (Fedora 43) with borgmatic installed using packages from Fedora, so I have pretty recent version: ``` $ borgmatic --version 2.0.10 ``` What I also have, is default btrfs partition layout. I want to backup root and /home partitions: ``` $ sudo btrfs subvolume list / ID 256 gen 11419 top level 5 path @ ID 257 gen 11419 top level 5 path @home ID 258 gen 9806 top level 5 path @swap ID 277 gen 10681 top level 257 path @home/.borgmatic-snapshot-18546/home ID 279 gen 11390 top level 256 path .borgmatic-snapshot-7335 ``` However, unless I provide two separate configs /etc/borgmatic.d/{root,home}.yaml with exactly the same configs but different path, borgmatic always backups up only the root partition. The order in the configuration file doesn't matter - home can be first, root can be first - only root is processed. If /home is the only provided path, then /home is processed properly. When separate config files are provided in borgmatic.d folder, then both files are processed properly, but result is not exactly what I expect due to following reasons: 1. Result is two separate backups 2. Second snapshot is created only after the first backup is fully processed. What I would prefer to see is to create both snapshots at the same time to avoid data corruption / misalignment. I do realize that I somewhat abuse borgmatic.d functionality as its main usecase is meant for separate repositories, but this workaround seems to be the only option I found thus far to get both root and /home backed up. Thank you for this great tool. Documentation is actually outstanding and borgmatic has a lot of nice features! And I realize I might be missing something trivial here. ### Steps to reproduce ``` source_directories: - / - /home repositories: - path: <REMOVED_SSH_PATH> exclude_patterns: - /dev - /proc - /sys - /run - /tmp - /var/tmp - /lost+found - /mnt - /media encryption_passphrase: <REMOVED_PASSPHRASE> keep_daily: 7 keep_weekly: 4 keep_monthly: 6 checks: - name: repository frequency: 2 weeks btrfs: ``` ### Actual behavior ``` $ sudo borgmatic create --verbosity 2 | tee borgmatic_combined.txt /etc/borgmatic/config.yaml: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg --version --debug --show-rc /etc/borgmatic/config.yaml: Borg 1.4.2 ssh://<REMOVED_SSH_PATH>: Running actions for repository ssh://<REMOVED_SSH_PATH>: Creating archive ssh://<REMOVED_SSH_PATH>: Using runtime directory /tmp/borgmatic-ppp86eb_/borgmatic ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: btrfs subvolume show / ssh://<REMOVED_SSH_PATH>: btrfs property get -t subvol / ro ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume ssh://<REMOVED_SSH_PATH>: Looking for snapshots to remove in /.borgmatic-snapshot-* ssh://<REMOVED_SSH_PATH>: Deleting Btrfs snapshot /.borgmatic-snapshot-18546 ssh://<REMOVED_SSH_PATH>: btrfs subvolume delete /.borgmatic-snapshot-18546 Delete subvolume 278 (no-commit): '//.borgmatic-snapshot-18546' ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function dump_data_sources ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function dump_data_sources ssh://<REMOVED_SSH_PATH>: Snapshotting Btrfs subvolumes ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume ssh://<REMOVED_SSH_PATH>: Creating Btrfs snapshot for / subvolume ssh://<REMOVED_SSH_PATH>: btrfs subvolume snapshot -r / /.borgmatic-snapshot-7335 Create readonly snapshot of '/' in '/.borgmatic-snapshot-7335' ssh://<REMOVED_SSH_PATH>: Writing patterns to /tmp/borgmatic-ppp86eb_/borgmatic/tmp9lbe9ck8: ! fm:/.borgmatic-snapshot-7335/.borgmatic-snapshot-7335 R /etc/borgmatic/config.yaml + /etc/borgmatic/config.yaml R /tmp/borgmatic-ppp86eb_/./borgmatic/bootstrap + /tmp/borgmatic-ppp86eb_/./borgmatic/bootstrap R /.borgmatic-snapshot-7335/./ + /.borgmatic-snapshot-7335/./ ! fm:/dev ! fm:/proc ! fm:/sys ! fm:/run ! fm:/tmp ! fm:/.borgmatic-snapshot-7335/./var/tmp ! fm:/.borgmatic-snapshot-7335/./lost+found ! fm:/.borgmatic-snapshot-7335/./mnt ! fm:/.borgmatic-snapshot-7335/./media ssh://<REMOVED_SSH_PATH>: Checking file paths Borg plans to include ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-ppp86eb_/borgmatic/tmp9lbe9ck8 ssh://<REMOVED_SSH_PATH>::{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f} --dry-run --list ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-ppp86eb_/borgmatic/tmp9lbe9ck8 --debug --show-rc ssh://<REMOVED_SSH_PATH>::{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f} using builtin fallback logging configuration 33 self tests completed in 0.05 seconds SSH command line: ['ssh', '-p', '1272', 'borg@<REMOVED_IP>', 'borg', 'serve', '--debug'] Remote: using builtin fallback logging configuration Remote: 33 self tests completed in 0.06 seconds Remote: using builtin fallback logging configuration Remote: Initialized logging system for JSON-based protocol Remote: Resolving repository path b'<REMOVED_PATH>borg' Remote: Resolved repository path to '<REMOVED_PATH>borg' Remote: Verified integrity of <REMOVED_PATH>borg/index.250 TAM-verified manifest security: read previous location 'ssh://<REMOVED_SSH_PATH>' security: read manifest timestamp '2025-11-27T00:20:10.278222' security: determined newest manifest timestamp as 2025-11-27T00:20:10.278222 security: repository checks ok, allowing access Creating archive at "ssh://<REMOVED_SSH_PATH>::PMR-NOBARA-2025-11-27T19:03:35.719220" Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/chunks Reading files cache ... Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/files security: read previous location 'ssh://<REMOVED_SSH_PATH>' security: read manifest timestamp '2025-11-27T00:20:10.278222' security: determined newest manifest timestamp as 2025-11-27T00:20:10.278222 security: repository checks ok, allowing access Processing files ... Remote: Cleaned up 0 uncommitted segment files (== everything after segment 250). Remote: Verified integrity of <REMOVED_PATH>borg/hints.250 Remote: check_free_space: required bytes 666483458, free bytes 3618791550976 security: saving state for c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654 to /root/.config/borg/security/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654 security: current location ssh://<REMOVED_SSH_PATH> security: key type 5 security: manifest timestamp 2025-11-27T18:06:13.422235 RemoteRepository: 307.25 MB bytes sent, 5.85 kB bytes received, 228 messages sent terminating with success status, rc 0 ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap ssh://<REMOVED_SSH_PATH>: Removing bootstrap manifest at /tmp/borgmatic-ppp86eb_/borgmatic/bootstrap/manifest.json ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps summary: /etc/borgmatic/config.yaml: Loading configuration file /etc/borgmatic/config.yaml: Successfully ran configuration file ``` ### Expected behavior I would expect to process both /home and root with given config file. ### Other notes / implementation ideas Nothing comes to mind :) ### borgmatic version 2.0.10 ### borgmatic installation method Fedora package ### Borg version 1.4.2 ### Python version Python 3.14.0 ### Database version (if applicable) not applicable / no database being backed up ### Operating system and version Nobara Linux 43 (KDE Plasma Desktop Edition)
Owner

Thanks for all the details here! What do you get when you run btrfs subvolume show /home? And also btrfs subvolume show /? That's what borgmatic uses (since 2.0.9 anyway) to determine which source directories are Btrfs subvolumes.

Thanks for all the details here! What do you get when you run `btrfs subvolume show /home`? And also `btrfs subvolume show /`? That's what borgmatic uses (since 2.0.9 anyway) to determine which source directories are Btrfs subvolumes.
Owner

I do realize that I somewhat abuse borgmatic.d functionality as its main usecase is meant for separate repositories, but this workaround seems to be the only option I found thus far to get both root and /home backed up.

FYI the borgmatic.d functionality isn't just for separate repositories; it can be used for any situation in which you want multiple backups with different borgmatic options. Having said that though, you ideally shouldn't have to use it here.

> I do realize that I somewhat abuse borgmatic.d functionality as its main usecase is meant for separate repositories, but this workaround seems to be the only option I found thus far to get both root and /home backed up. FYI the borgmatic.d functionality isn't just for separate repositories; it can be used for any situation in which you want multiple backups with different borgmatic options. Having said that though, you ideally shouldn't have to use it here.
Author

Hey @witten ! Thank you for very quick response. Unfortunately I couldn't get back sooner as I wasn't able to turn this PC on remotely and I had to do some troubleshooting to find that I had bad memory contact - one of the sticks needed reseating and only now I found time to do the troubleshooting. Also, I had problems previously pasting the logs as it would eat all newlines, so I converted the newlines to linux format and it seems ok now.

Anyway, to reply your question, here is the output of the commands:

$ sudo btrfs subvolume show /
@
        Name:                   @
        UUID:                   69a82dd6-2876-0649-84ac-145229a858e5
        Parent UUID:            -
        Received UUID:          -
        Creation time:          2025-07-25 00:02:05 +0200
        Subvolume ID:           256
        Generation:             11533
        Gen at creation:        11
        Parent ID:              5
        Top level ID:           5
        Flags:                  -
        Send transid:           0
        Send time:              2025-07-25 00:02:05 +0200
        Receive transid:        0
        Receive time:           -
        Snapshot(s):
                                @/.borgmatic-snapshot-1711
        Quota group:            n/a
$ sudo btrfs subvolume show /home
@home
        Name:                   @home
        UUID:                   0ac0b23c-6eec-f945-a646-4a16889b6463
        Parent UUID:            -
        Received UUID:          -
        Creation time:          2025-07-25 00:02:05 +0200
        Subvolume ID:           257
        Generation:             11532
        Gen at creation:        11
        Parent ID:              5
        Top level ID:           5
        Flags:                  -
        Send transid:           0
        Send time:              2025-07-25 00:02:05 +0200
        Receive transid:        0
        Receive time:           -
        Snapshot(s):
                                @home/.borgmatic-snapshot-18546/home
        Quota group:            n/a
Hey @witten ! Thank you for very quick response. Unfortunately I couldn't get back sooner as I wasn't able to turn this PC on remotely and I had to do some troubleshooting to find that I had bad memory contact - one of the sticks needed reseating and only now I found time to do the troubleshooting. Also, I had problems previously pasting the logs as it would eat all newlines, so I converted the newlines to linux format and it seems ok now. Anyway, to reply your question, here is the output of the commands: ``` $ sudo btrfs subvolume show / @ Name: @ UUID: 69a82dd6-2876-0649-84ac-145229a858e5 Parent UUID: - Received UUID: - Creation time: 2025-07-25 00:02:05 +0200 Subvolume ID: 256 Generation: 11533 Gen at creation: 11 Parent ID: 5 Top level ID: 5 Flags: - Send transid: 0 Send time: 2025-07-25 00:02:05 +0200 Receive transid: 0 Receive time: - Snapshot(s): @/.borgmatic-snapshot-1711 Quota group: n/a ``` ``` $ sudo btrfs subvolume show /home @home Name: @home UUID: 0ac0b23c-6eec-f945-a646-4a16889b6463 Parent UUID: - Received UUID: - Creation time: 2025-07-25 00:02:05 +0200 Subvolume ID: 257 Generation: 11532 Gen at creation: 11 Parent ID: 5 Top level ID: 5 Flags: - Send transid: 0 Send time: 2025-07-25 00:02:05 +0200 Receive transid: 0 Receive time: - Snapshot(s): @home/.borgmatic-snapshot-18546/home Quota group: n/a ```
Owner

Glad to hear it sounds like you've got both your memory sticks and newlines sorted out! Thanks for including the output. Based on that, I don't know why one of the subvolumes would get detected and the other wouldn't. I tried to set up a local repro with one subvolume contained inside the other—the containing subvolume with an @ name and a separate mount point—and I wasn't able to get the behavior you're seeing even with borgmatic 2.0.10. The only thing I can think of is that one of your subvolumes being at / is causing a difference here. Looking at the code though, it should handle that case.

I assume that both your btrfs subvolume show commands above exit without error? If you're using Bash, running echo $? immediately after a command will show its exit status (which would be 0 for success).

What I can do is create an instrumented version of btrfs.py from borgmatic's source with additional debug logs. Then, if you feel comfortable, you can drop it into your local borgmatic install and get those additional logs.

Glad to hear it sounds like you've got both your memory sticks and newlines sorted out! Thanks for including the output. Based on that, I don't know why one of the subvolumes would get detected and the other wouldn't. I tried to set up a local repro with one subvolume contained inside the other—the containing subvolume with an `@` name and a separate mount point—and I wasn't able to get the behavior you're seeing even with borgmatic 2.0.10. The only thing I can think of is that one of your subvolumes being at `/` is causing a difference here. Looking at the code though, it *should* handle that case. I assume that both your `btrfs subvolume show` commands above exit without error? If you're using Bash, running `echo $?` immediately after a command will show its exit status (which would be `0` for success). What I can do is create an instrumented version of `btrfs.py` from borgmatic's source with additional debug logs. Then, if you feel comfortable, you can drop it into your local borgmatic install and get those additional logs.
Owner

Attached is an instrumented btrfs.py based on borgmatic 2.0.10. You should be able to replace the existing borgmatic/hooks/data_source/btrfs.py installed by your Fedora package with this altered version. (You can always reinstall the package to revert the changes.) When running borgmatic, look for new log lines containing with #1192: to verify that it's working. And then if you could include the full log output here (redacted as necessary), that would be great. Thanks for your patience!

Attached is an instrumented `btrfs.py` based on borgmatic 2.0.10. You should be able to replace the existing `borgmatic/hooks/data_source/btrfs.py` installed by your Fedora package with this altered version. (You can always reinstall the package to revert the changes.) When running borgmatic, look for new log lines containing with `#1192:` to verify that it's working. And then if you could include the full log output here (redacted as necessary), that would be great. Thanks for your patience!
16 KiB
Author

hello again,
I confirmed that both sudo btrfs subvolume show /home and sudo btrfs subvolume show / return with 0 error code.

I applied changed btrfs.py file here: /usr/lib/python3.14/site-packages/borgmatic/hooks/data_source/ and I do see updated log entries:

$ sudo borgmatic create --verbosity 2 | tee borgmatic_1192.txt
/etc/borgmatic/config.yaml: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg --version --debug --show-rc
/etc/borgmatic/config.yaml: Borg 1.4.2
ssh://<REMOVED_SSH_PATH>: Running actions for repository
ssh://<REMOVED_SSH_PATH>: Creating archive
ssh://<REMOVED_SSH_PATH>: Using runtime directory /tmp/borgmatic-pqrr65z2/borgmatic
ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap
ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: #1192: get_containing_subvolume_path(), btrfs_command: "btrfs", path: "/"
ssh://<REMOVED_SSH_PATH>: #1192:    candiate path: /
ssh://<REMOVED_SSH_PATH>: #1192: path_is_a_subvolume(), btrfs_command: "btrfs", path: "/"
ssh://<REMOVED_SSH_PATH>: btrfs subvolume show /
ssh://<REMOVED_SSH_PATH>: #1192:    success
ssh://<REMOVED_SSH_PATH>: #1192:        candiate path IS a subvolume
ssh://<REMOVED_SSH_PATH>: btrfs property get -t subvol / ro
ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume
ssh://<REMOVED_SSH_PATH>: Looking for snapshots to remove in /.borgmatic-snapshot-*
ssh://<REMOVED_SSH_PATH>: Deleting Btrfs snapshot /.borgmatic-snapshot-1926
ssh://<REMOVED_SSH_PATH>: btrfs subvolume delete /.borgmatic-snapshot-1926
Delete subvolume 284 (no-commit): '//.borgmatic-snapshot-1926'
ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps
ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function dump_data_sources
ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function dump_data_sources
ssh://<REMOVED_SSH_PATH>: Snapshotting Btrfs subvolumes
ssh://<REMOVED_SSH_PATH>: #1192: get_containing_subvolume_path(), btrfs_command: "btrfs", path: "/"
ssh://<REMOVED_SSH_PATH>: #1192:    candiate path: /
ssh://<REMOVED_SSH_PATH>: #1192:        candiate path IS a subvolume
ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume
ssh://<REMOVED_SSH_PATH>: Creating Btrfs snapshot for / subvolume
ssh://<REMOVED_SSH_PATH>: btrfs subvolume snapshot -r / /.borgmatic-snapshot-7947
Create readonly snapshot of '/' in '/.borgmatic-snapshot-7947'
ssh://<REMOVED_SSH_PATH>: Writing patterns to /tmp/borgmatic-pqrr65z2/borgmatic/tmpiiqofwo3:
! fm:/.borgmatic-snapshot-7947/.borgmatic-snapshot-7947
R /etc/borgmatic/config.yaml
+ /etc/borgmatic/config.yaml
R /tmp/borgmatic-pqrr65z2/./borgmatic/bootstrap
+ /tmp/borgmatic-pqrr65z2/./borgmatic/bootstrap
R /.borgmatic-snapshot-7947/./
+ /.borgmatic-snapshot-7947/./
! fm:/dev
! fm:/proc
! fm:/sys
! fm:/run
! fm:/tmp
! fm:/.borgmatic-snapshot-7947/./var/tmp
! fm:/.borgmatic-snapshot-7947/./lost+found
! fm:/.borgmatic-snapshot-7947/./mnt
! fm:/.borgmatic-snapshot-7947/./media
ssh://<REMOVED_SSH_PATH>: Checking file paths Borg plans to include
ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-pqrr65z2/borgmatic/tmpiiqofwo3 ssh://<REMOVED_SSH_PATH>::{hostname}-root-{now:%Y-%m-%dT%H:%M:%S.%f} --dry-run --list
ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-pqrr65z2/borgmatic/tmpiiqofwo3 --debug --show-rc ssh://<REMOVED_SSH_PATH>::{hostname}-root-{now:%Y-%m-%dT%H:%M:%S.%f}
using builtin fallback logging configuration
33 self tests completed in 0.05 seconds
SSH command line: ['ssh', '-p', '1272', 'borg@<REMOVED_IP>', 'borg', 'serve', '--debug']
Remote: using builtin fallback logging configuration
Remote: 33 self tests completed in 0.06 seconds
Remote: using builtin fallback logging configuration
Remote: Initialized logging system for JSON-based protocol
Remote: Resolving repository path b'<REMOVED_PATH>borg'
Remote: Resolved repository path to '<REMOVED_PATH>borg'
Remote: Verified integrity of <REMOVED_PATH>borg/index.287
TAM-verified manifest
security: read previous location 'ssh://<REMOVED_SSH_PATH>'
security: read manifest timestamp '2025-11-29T11:06:52.360870'
security: determined newest manifest timestamp as 2025-11-29T11:06:52.360870
security: repository checks ok, allowing access
Creating archive at "ssh://<REMOVED_SSH_PATH>::PMR-NOBARA-root-2025-11-29T12:20:47.529249"
Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/chunks
Reading files cache ...
Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/files
security: read previous location 'ssh://<REMOVED_SSH_PATH>'
security: read manifest timestamp '2025-11-29T11:06:52.360870'
security: determined newest manifest timestamp as 2025-11-29T11:06:52.360870
security: repository checks ok, allowing access
Processing files ...
Remote: Cleaned up 0 uncommitted segment files (== everything after segment 287).
Remote: Verified integrity of <REMOVED_PATH>borg/hints.287
Remote: check_free_space: few segments, not requiring a full free segment
Remote: check_free_space: calculated working space for compact as 24 bytes
Remote: check_free_space: required bytes 121223662, free bytes 3575449661440
security: saving state for c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654 to /root/.config/borg/security/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654
security: current location   ssh://<REMOVED_SSH_PATH>
security: key type           5
security: manifest timestamp 2025-11-29T11:23:30.178647
RemoteRepository: 443.72 MB bytes sent, 6.66 kB bytes received, 238 messages sent
terminating with success status, rc 0
ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap
ssh://<REMOVED_SSH_PATH>: Removing bootstrap manifest at /tmp/borgmatic-pqrr65z2/borgmatic/bootstrap/manifest.json
ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps
ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps
ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps
ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps
ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps

summary:
/etc/borgmatic/config.yaml: Loading configuration file
/etc/borgmatic/config.yaml: Successfully ran configuration file

I also have a little feedback for default configuration. With btrfs I also seem to be affected by #1163

I disabled all security features in borgmatic.service as without this, borgmatic didn't detect any btrfs subvolumes.

Also, with default timer configuration the behavior is not something that I would expect. This is default configuration I see for timer:

[Unit]
Description=Run borgmatic backup

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=3h

[Install]
WantedBy=timers.target

This means, that by default, the backup job should be scheduled each day between 00:00 and 03:00 and my PC is never turned on at these hours. This should be remediated by Persistent=true parameter which will make sure, that if some instance is missed, next backup should be scheduled at next boot. But unfortunately, "RandomizedDelaySec" is also applied in such scenario, which means that next backup run might actually not happen if my PC will be turned off before 0-3h random timeout runs out (please see https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html#Persistent=).

For me the solution was to change RandomizedDelaySec=3h to RandomizedDelaySec=3m, but maybe there is better solution to this case.

hello again, I confirmed that both `sudo btrfs subvolume show /home` and `sudo btrfs subvolume show /` return with `0` error code. I applied changed `btrfs.py` file here: `/usr/lib/python3.14/site-packages/borgmatic/hooks/data_source/` and I do see updated log entries: ``` $ sudo borgmatic create --verbosity 2 | tee borgmatic_1192.txt /etc/borgmatic/config.yaml: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg --version --debug --show-rc /etc/borgmatic/config.yaml: Borg 1.4.2 ssh://<REMOVED_SSH_PATH>: Running actions for repository ssh://<REMOVED_SSH_PATH>: Creating archive ssh://<REMOVED_SSH_PATH>: Using runtime directory /tmp/borgmatic-pqrr65z2/borgmatic ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: #1192: get_containing_subvolume_path(), btrfs_command: "btrfs", path: "/" ssh://<REMOVED_SSH_PATH>: #1192: candiate path: / ssh://<REMOVED_SSH_PATH>: #1192: path_is_a_subvolume(), btrfs_command: "btrfs", path: "/" ssh://<REMOVED_SSH_PATH>: btrfs subvolume show / ssh://<REMOVED_SSH_PATH>: #1192: success ssh://<REMOVED_SSH_PATH>: #1192: candiate path IS a subvolume ssh://<REMOVED_SSH_PATH>: btrfs property get -t subvol / ro ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume ssh://<REMOVED_SSH_PATH>: Looking for snapshots to remove in /.borgmatic-snapshot-* ssh://<REMOVED_SSH_PATH>: Deleting Btrfs snapshot /.borgmatic-snapshot-1926 ssh://<REMOVED_SSH_PATH>: btrfs subvolume delete /.borgmatic-snapshot-1926 Delete subvolume 284 (no-commit): '//.borgmatic-snapshot-1926' ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function dump_data_sources ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function dump_data_sources ssh://<REMOVED_SSH_PATH>: Snapshotting Btrfs subvolumes ssh://<REMOVED_SSH_PATH>: #1192: get_containing_subvolume_path(), btrfs_command: "btrfs", path: "/" ssh://<REMOVED_SSH_PATH>: #1192: candiate path: / ssh://<REMOVED_SSH_PATH>: #1192: candiate path IS a subvolume ssh://<REMOVED_SSH_PATH>: Path / is a Btrfs subvolume ssh://<REMOVED_SSH_PATH>: Creating Btrfs snapshot for / subvolume ssh://<REMOVED_SSH_PATH>: btrfs subvolume snapshot -r / /.borgmatic-snapshot-7947 Create readonly snapshot of '/' in '/.borgmatic-snapshot-7947' ssh://<REMOVED_SSH_PATH>: Writing patterns to /tmp/borgmatic-pqrr65z2/borgmatic/tmpiiqofwo3: ! fm:/.borgmatic-snapshot-7947/.borgmatic-snapshot-7947 R /etc/borgmatic/config.yaml + /etc/borgmatic/config.yaml R /tmp/borgmatic-pqrr65z2/./borgmatic/bootstrap + /tmp/borgmatic-pqrr65z2/./borgmatic/bootstrap R /.borgmatic-snapshot-7947/./ + /.borgmatic-snapshot-7947/./ ! fm:/dev ! fm:/proc ! fm:/sys ! fm:/run ! fm:/tmp ! fm:/.borgmatic-snapshot-7947/./var/tmp ! fm:/.borgmatic-snapshot-7947/./lost+found ! fm:/.borgmatic-snapshot-7947/./mnt ! fm:/.borgmatic-snapshot-7947/./media ssh://<REMOVED_SSH_PATH>: Checking file paths Borg plans to include ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-pqrr65z2/borgmatic/tmpiiqofwo3 ssh://<REMOVED_SSH_PATH>::{hostname}-root-{now:%Y-%m-%dT%H:%M:%S.%f} --dry-run --list ssh://<REMOVED_SSH_PATH>: BORG_PASSPHRASE_FD=*** BORG_DEBUG_PASSPHRASE=*** BORG_DISPLAY_PASSPHRASE=*** BORG_RELOCATED_REPO_ACCESS_IS_OK=*** BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=*** BORG_USE_CHUNKS_ARCHIVE=*** BORG_EXIT_CODES=*** borg create --patterns-from /tmp/borgmatic-pqrr65z2/borgmatic/tmpiiqofwo3 --debug --show-rc ssh://<REMOVED_SSH_PATH>::{hostname}-root-{now:%Y-%m-%dT%H:%M:%S.%f} using builtin fallback logging configuration 33 self tests completed in 0.05 seconds SSH command line: ['ssh', '-p', '1272', 'borg@<REMOVED_IP>', 'borg', 'serve', '--debug'] Remote: using builtin fallback logging configuration Remote: 33 self tests completed in 0.06 seconds Remote: using builtin fallback logging configuration Remote: Initialized logging system for JSON-based protocol Remote: Resolving repository path b'<REMOVED_PATH>borg' Remote: Resolved repository path to '<REMOVED_PATH>borg' Remote: Verified integrity of <REMOVED_PATH>borg/index.287 TAM-verified manifest security: read previous location 'ssh://<REMOVED_SSH_PATH>' security: read manifest timestamp '2025-11-29T11:06:52.360870' security: determined newest manifest timestamp as 2025-11-29T11:06:52.360870 security: repository checks ok, allowing access Creating archive at "ssh://<REMOVED_SSH_PATH>::PMR-NOBARA-root-2025-11-29T12:20:47.529249" Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/chunks Reading files cache ... Verified integrity of /root/.cache/borg/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654/files security: read previous location 'ssh://<REMOVED_SSH_PATH>' security: read manifest timestamp '2025-11-29T11:06:52.360870' security: determined newest manifest timestamp as 2025-11-29T11:06:52.360870 security: repository checks ok, allowing access Processing files ... Remote: Cleaned up 0 uncommitted segment files (== everything after segment 287). Remote: Verified integrity of <REMOVED_PATH>borg/hints.287 Remote: check_free_space: few segments, not requiring a full free segment Remote: check_free_space: calculated working space for compact as 24 bytes Remote: check_free_space: required bytes 121223662, free bytes 3575449661440 security: saving state for c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654 to /root/.config/borg/security/c19f0ebb2ac155de04e61c98d4e61dc1a0366a45469e3bf44a6b0bdc43d3d654 security: current location ssh://<REMOVED_SSH_PATH> security: key type 5 security: manifest timestamp 2025-11-29T11:23:30.178647 RemoteRepository: 443.72 MB bytes sent, 6.66 kB bytes received, 238 messages sent terminating with success status, rc 0 ssh://<REMOVED_SSH_PATH>: Calling bootstrap hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Looking for bootstrap manifest files to remove in /tmp/borgmatic-*/borgmatic/bootstrap ssh://<REMOVED_SSH_PATH>: Removing bootstrap manifest at /tmp/borgmatic-pqrr65z2/borgmatic/bootstrap/manifest.json ssh://<REMOVED_SSH_PATH>: Calling btrfs hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling lvm hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Calling mariadb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MariaDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mongodb hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MongoDB data source dumps ssh://<REMOVED_SSH_PATH>: Calling mysql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing MySQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling postgresql hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing PostgreSQL data source dumps ssh://<REMOVED_SSH_PATH>: Calling sqlite hook function remove_data_source_dumps ssh://<REMOVED_SSH_PATH>: Removing SQLite data source dumps ssh://<REMOVED_SSH_PATH>: Calling zfs hook function remove_data_source_dumps summary: /etc/borgmatic/config.yaml: Loading configuration file /etc/borgmatic/config.yaml: Successfully ran configuration file ``` I also have a little feedback for default configuration. With btrfs I also seem to be affected by https://projects.torsion.org/borgmatic-collective/borgmatic/issues/1163 I disabled all security features in borgmatic.service as without this, borgmatic didn't detect any btrfs subvolumes. Also, with default timer configuration the behavior is not something that I would expect. This is default configuration I see for timer: ``` [Unit] Description=Run borgmatic backup [Timer] OnCalendar=daily Persistent=true RandomizedDelaySec=3h [Install] WantedBy=timers.target ``` This means, that by default, the backup job should be scheduled each day between 00:00 and 03:00 and my PC is never turned on at these hours. This should be remediated by `Persistent=true` parameter which will make sure, that if some instance is missed, next backup should be scheduled at next boot. But unfortunately, "RandomizedDelaySec" is also applied in such scenario, which means that next backup run might actually not happen if my PC will be turned off before 0-3h random timeout runs out (please see [https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html#Persistent=](https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html#Persistent=)). For me the solution was to change RandomizedDelaySec=3h to RandomizedDelaySec=3m, but maybe there is better solution to this case.
Owner

Thanks for doing that. So what those most recent logs indicate is that "/home" was completely absent in the patterns by the time borgmatic got to the instrumented code—not what I was suspecting! But the good news is that based on that, I tried something locally on a hunch: I put / (not a Btrfs subvolume on my system) and /an/actual/btrfs/subvolume into my source directories and ran borgmatic with Btrfs enabled. The actual Btrfs subvolume vanished from patterns and only / got passed into the Btrfs hook, which is similar to the behavior you're seeing. So I might have a partial repro here. I'll dig into this further and try to determine how having / in source directories is causing patterns to vanish. (EDIT: I tracked down the problem to a function called deduplicate_runtime_directory_patterns(). Now the question is what to do about it.)

I disabled all security features in borgmatic.service as without this, borgmatic didn't detect any btrfs subvolumes.

Interesting. Were you able to narrow down exactly which options were causing problems? For instance, if you reintroduce the security options one by one (or half at a time, if you want to binary search), does that pinpoint the issue? In #1163 for LVM, it sounded like PrivateDevices/ProtectKernelModules may be impacting things.

For me the solution was to change RandomizedDelaySec=3h to RandomizedDelaySec=3m, but maybe there is better solution to this case.

Great point. Seems like a reasonable change to me. (I set this to "10m" in main.)

Thanks for doing that. So what those most recent logs indicate is that "/home" was completely absent in the patterns by the time borgmatic got to the instrumented code—not what I was suspecting! But the good news is that based on that, I tried something locally on a hunch: I put `/` (not a Btrfs subvolume on my system) and `/an/actual/btrfs/subvolume` into my source directories and ran borgmatic with Btrfs enabled. The actual Btrfs subvolume vanished from patterns and only `/` got passed into the Btrfs hook, which is similar to the behavior you're seeing. So I might have a partial repro here. I'll dig into this further and try to determine how having `/` in source directories is causing patterns to vanish. (EDIT: I tracked down the problem to a function called `deduplicate_runtime_directory_patterns()`. Now the question is what to do about it.) > I disabled all security features in borgmatic.service as without this, borgmatic didn't detect any btrfs subvolumes. Interesting. Were you able to narrow down exactly which options were causing problems? For instance, if you reintroduce the security options one by one (or half at a time, if you want to binary search), does that pinpoint the issue? In #1163 for LVM, it sounded like `PrivateDevices`/`ProtectKernelModules` may be impacting things. > For me the solution was to change RandomizedDelaySec=3h to RandomizedDelaySec=3m, but maybe there is better solution to this case. Great point. Seems like a reasonable change to me. (I set this to "10m" in main.)
Author

I will play with options and leave feedback. Is there something I could do to determine the solution in deduplicate_runtime_directory_patterns? I am not a developer, but might try to understand the logic and actual problem. Will read the code later today.

I will play with options and leave feedback. Is there something I could do to determine the solution in deduplicate_runtime_directory_patterns? I am not a developer, but might try to understand the logic and actual problem. Will read the code later today.
Author

I started enabling options one by one. Enabling PrivateDevices or ProtectKernelModules does not impact detecting of btrfs volumes. Setting CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW results in borgmatic not being able to detect btrfs subvolumes.

Then I downloaded default service, removed the 1m timer, changed the path to match binary location on my system, removed the "borgmatic.pw" line and then commented out CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW. Then btrfs subvolumes were detected properly.

So actually, on my system, this is the only option which stops the btrfs detection.

I started enabling options one by one. Enabling `PrivateDevices` or `ProtectKernelModules` does not impact detecting of btrfs volumes. Setting `CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW` results in borgmatic not being able to detect btrfs subvolumes. Then I downloaded default service, removed the 1m timer, changed the path to match binary location on my system, removed the "borgmatic.pw" line and then commented out `CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW`. Then btrfs subvolumes were detected properly. So actually, on my system, this is the only option which stops the btrfs detection.
Owner

I will play with options and leave feedback. Is there something I could do to determine the solution in deduplicate_runtime_directory_patterns? I am not a developer, but might try to understand the logic and actual problem. Will read the code later today.

You're welcome to have a look, but this function is unfortunately pretty thorny and complex—which is probably how a bug crept in to begin with. 😅 But the good news is I think I have a lead on a potential fix. This code isn't handling an edge case in the deduplication (when two potential duplicate patterns overlap and one of of them contains the runtime directory), and that apparently leads to the behavior you're seeing with one pattern getting over-aggressively deduplicated.

I started enabling options one by one. Enabling PrivateDevices nor ProtectKernelModules does not impact detecting of btrfs volumes. Setting CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW results in borgmatic not being able to detect btrfs subvolumes.

Then I downloaded default service, removed the 1m timer, changed the path to match binary location on my system, removed the "borgmatic.pw" line and then commented out CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW. Then btrfs subvolumes were detected properly.

So actually, on my system, this is the only option which stops the backups.

Cool, thanks for diagnosing that. I'll update the documentation / sample systemd service accordingly as part of this ticket!

> I will play with options and leave feedback. Is there something I could do to determine the solution in deduplicate_runtime_directory_patterns? I am not a developer, but might try to understand the logic and actual problem. Will read the code later today. You're welcome to have a look, but this function is unfortunately pretty thorny and complex—which is probably how a bug crept in to begin with. 😅 But the good news is I think I have a lead on a potential fix. This code isn't handling an edge case in the deduplication (when two potential duplicate patterns overlap and one of of them contains the runtime directory), and that apparently leads to the behavior you're seeing with one pattern getting over-aggressively deduplicated. > I started enabling options one by one. Enabling `PrivateDevices` nor `ProtectKernelModules` does not impact detecting of btrfs volumes. Setting `CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW` results in borgmatic not being able to detect btrfs subvolumes. > > Then I downloaded default service, removed the 1m timer, changed the path to match binary location on my system, removed the "borgmatic.pw" line and then commented out `CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW`. Then btrfs subvolumes were detected properly. > > So actually, on my system, this is the only option which stops the backups. Cool, thanks for diagnosing that. I'll update the documentation / sample systemd service accordingly as part of this ticket!
Author

You're welcome to have a look, but this function is unfortunately pretty thorny and complex—which is probably how a bug crept in to begin with. 😅 But the good news is I think I have a lead on a potential fix. This code isn't handling an edge case in the deduplication (when two potential duplicate patterns overlap and one of of them contains the runtime directory), and that apparently leads to the behavior you're seeing with one pattern getting over-aggressively deduplicated.

Yeah... took a look, read function description and concluded that its definitely above my skills. Out of all things, all I could do is to provide mental support at this stage :) let me know if something could be tested though!

> You're welcome to have a look, but this function is unfortunately pretty thorny and complex—which is probably how a bug crept in to begin with. 😅 But the good news is I think I have a lead on a potential fix. This code isn't handling an edge case in the deduplication (when two potential duplicate patterns overlap and one of of them contains the runtime directory), and that apparently leads to the behavior you're seeing with one pattern getting over-aggressively deduplicated. Yeah... took a look, read function description and concluded that its definitely above my skills. Out of all things, all I could do is to provide mental support at this stage :) let me know if something could be tested though!
Owner

Okay, I've made a fix for this to the main branch that will be part of the next release! I'm pretty sure it will address your use case since I had a partial repro, but I would appreciate that you test it out after that release.

If you'd like to test it before then, you are welcome to as well. I've attached the updated borgmatic/actions/pattern.py source file that you can drop in as a replacement. (Make sure you are replacing that specific path and not any other one named pattern.py.) This is the version of that file from main, but it looks like it's identical in 2.0.10 (modulo the fix in this ticket) and so I imagine should work as well.

You can either leave the earlier btrfs.py debugging changes in place or not; they shouldn't impact the pattern.py changes.

Thanks!

Okay, I've made a fix for this to the main branch that will be part of the next release! I'm pretty sure it will address your use case since I had a partial repro, but I would appreciate that you test it out after that release. If you'd like to test it before then, you are welcome to as well. I've attached the updated `borgmatic/actions/pattern.py` source file that you can drop in as a replacement. (Make sure you are replacing that specific path and not any other one named `pattern.py`.) This is the version of that file from main, but it looks like it's identical in 2.0.10 (modulo the fix in this ticket) and so I imagine should work as well. You can either leave the earlier `btrfs.py` debugging changes in place or not; they shouldn't impact the `pattern.py` changes. Thanks!
Author

Hello @witten! I confirm that this issue is resolved by use of attached pattern.py file. As of now both paths are properly processed and I can use single /etc/borgmatic/config.yaml file! Thank you!

Hello @witten! I confirm that this issue is resolved by use of attached pattern.py file. As of now both paths are properly processed and I can use single `/etc/borgmatic/config.yaml` file! Thank you!
Owner

Awesome, I'm glad to hear that did it!

Awesome, I'm glad to hear that did it!
Owner

Released in borgmatic 2.0.13!

Released in borgmatic 2.0.13!
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
borgmatic-collective/borgmatic#1192
No description provided.