Hi,

few points below.

Maxim Cournoyer <maxim.courno...@gmail.com> writes:

> Hi Tanguy,
>
> "Tanguy Le Carrour" <tan...@bioneland.org> writes:
>
>> Hi Maxim, Hi Guix,
>>
>>
>> On Sun Mar 9, 2025 at 5:57 AM CET, Maxim Cournoyer wrote:
>>> "Tanguy Le Carrour" <tan...@bioneland.org> writes:
>>>
>>> [...]
>>>
>>>>> I'd migrate your system to the Btrfs file system, which dynamically
>>>>> allocates inodes and never runs out of them.  It has a few peculiarities
>>>>> that must be taken into account, such as the requirement to run 'btrfs
>>>>> balance' periodically to reclaim unallocated blocks, but otherwise it's
>>>>> stable and has interesting features.  Make sure to use it with Zstd
>>>>> compression to magically double (about) your storage capacity :-).
>>>>
>>>> Sounds like an **excellent** plan! I’ll give it a try at the week-end!
>>>> Can I actually do it from the installer? 🤔… well I guess I’ll figure it out
>>>> soon enough! 😅
>>>
>>> I think the installer supports creating and installing to Btrfs.  The
>>> compression options can always be added or changed at a later time.
>>
>> Long story short: I now have a brand new Guix System with a Btrfs root and
>> everything seems to be working quite well! 😁
>
> Excellent!  Just don't forget to run the 'btrfs balance /' command
> regularly, otherwise over time the allocated storage chunks of Btrfs
> gets all used up

I do not think this is necessary.  Yes, in case you get a really bad
case of over-allocation of chunks, the balance might be useful.  But in
my experience BTRFS these days is reasonably good in reusing the chunks.
On some systems I did not run the balance for many years, and everything
seems to still work fine.

The official wiki seems to support that[0].  Albeit this answer[1] on
unix stackexchange indicates the wiki is bit outdated:

--8<---------------cut here---------------start------------->8---
That particular FAQ entry on the wiki is slightly outdated. Current
mainline Linux kernels (4.14 as of this answer) have some degree of
automated cleanup, though I'm not sure which distros have new enough
kernels to provide that.
--8<---------------cut here---------------end--------------->8---

We have kernel bit newer then 4.14, so we should be good there.  So the
situation might be even better than wiki states.

> , despite what 'df' and other tools might say

One command you need to keep in your toolbox is `btrfs fi usage'.  

--8<---------------cut here---------------start------------->8---
# btrfs fi usage /
Overall:
    Device size:                 921.80GiB
    Device allocated:            441.07GiB
    Device unallocated:          480.73GiB
    Device missing:                  0.00B
    Device slack:                    0.00B
    Used:                        250.62GiB
    Free (estimated):            662.08GiB      (min: 421.71GiB)
    Free (statfs, df):           662.08GiB
    Data ratio:                       1.00
    Metadata ratio:                   2.00
    Global reserve:              387.73MiB      (used: 0.00B)
    Multiple profiles:                  no

Data,single: Size:427.01GiB, Used:245.66GiB (57.53%)
   /dev/lvm/data         427.01GiB

Metadata,DUP: Size:7.00GiB, Used:2.48GiB (35.41%)
   /dev/lvm/data          14.00GiB

System,DUP: Size:32.00MiB, Used:64.00KiB (0.20%)
   /dev/lvm/data          64.00MiB

Unallocated:
   /dev/lvm/data         480.73GiB
--8<---------------cut here---------------end--------------->8---

Notice the `min: ' field.  That tells you how much data you can store in
the worst case.

(These numbers are from my laptop, which regularly dips below 200 GiB
estimated free space, and I do not run balance at all.  So *some*
auto-cleanup is definitely happening.)

> , and this is an annoying situation to recover from.

Yes, running out of free space on BTRFS is bit annoying to recover from.
There is a neat little trick, when you temporarily add an USB drive to
the filesystem as additional device, which allows you to delete some
data.  But that still is annoying, so I am using the following cron to
give me a warning if I am running out of space:

--8<---------------cut here---------------start------------->8---
           (cron-timer 'cron-btrfs-free-space
                       "0 21 * * *"
                       (script/btrfs-free-space "/"))
--8<---------------cut here---------------end--------------->8---

The procedure for the script is:

--8<---------------cut here---------------start------------->8---
(define* (script/btrfs-free-space path
                                  #:optional
                                  ;; There should be at least 100 GB free.
                                  (threshold (* 100 1024 1024 1024)))
  "Return a script to check whether BTRFS at @var{path} has at least
@var{threshold} free (min) space."
  (let ((btrfs (file-append btrfs-progs "/bin/btrfs"))
        (grep (file-append grep "/bin/grep"))
        (awk (file-append mawk "/bin/mawk"))
        (tr (file-append coreutils-minimal "/bin/tr")))
    (program-file/sh
     (string-append "btrfs-free-space-" (string-replace-substring path "/" "-"))
     "[ \"$( "
     btrfs " fi usage -b " path
     " | " grep " -F 'Free (estimated)'"
     " | " awk " '{print $5}'"
     " | " tr " -d ')'"
     ")\" -lt " (number->string threshold) " ]"
     " && " btrfs " fi usage -T " path
     " ||:")))
--8<---------------cut here---------------end--------------->8---

The `cron-timer' procedure is basically just shepherd timer with support
for sending emails, details in this[2] blog post.

>
> Here are some btrfs-related jobs I use:
>
> (define btrfs-balance-job
>   ;; Re-allocate chunks which are using less than 5% of their chunk
>   ;; space, to regain Btrfs 'unallocated' space.  The usage is kept
>   ;; low (5%) to minimize wear on the SSD.  Runs at 12 PM every 3 days.
>   #~(job '(next-hour-from (next-day (range 1 31 3)) '(12))
>          (lambda ()
>            (system* #$(file-append btrfs-progs "/bin/btrfs")
>                     "balance" "start" "-dusage=5" "/"))
>          "btrfs-balance"))

Already commented on above.

>
> (define btrfs-scrub-job
>   ;; Scans the whole disk data to detect and repair errors.  Runs at 12
>   ;; AM monthly.

This one is great, and I have similar one (albeit I run it once a week).

I am sure you are aware, but other readers might get confused, so I
would like to point out that the "repair errors" part of the comment is
subject to some conditions.  In particular, scrub can repair errors only
when there is an additional copy of the data needing a repair.  So
either `dup' or (some of) the RAID profiles.  For example in the
"default" format (-d single -m dup), only metadata errors can be
repaired.  Which *is* useful, at least you can `ls' to see what files
are corrupted, but it is a limitation to be aware of.

>   #~(job '(next-hour-from (next-month) '(12))
>          (lambda ()
>            (system* #$(file-append btrfs-progs "/bin/btrfs")
>                     "scrub" "start" "-c3" "/"))
>          "btrfs-scrub"))
>
> (define btrbk-job
>   #~(job '(next-hour)
>          (lambda ()
>            (system* #$(file-append btrbk "/bin/btrbk")
>                     "-q" "-c" #$(local-file "btrbk.conf") "run"))
>          "btrbk"))

I do backup in a boring way (just dd the whole disk), so no comment
here. :)

One additional cron I have is checking the error counts:

--8<---------------cut here---------------start------------->8---
(define (script/btrfs-error-counts path)
  "Return a script to check BTRFS error counts at @var{path}."
  (program-file/sh
   (string-append "btrfs-error-counts-" (string-replace-substring path "/" "-"))
   btrfs-progs "/bin/btrfs device stats " path
   " | " sed "/bin/sed '/^$/d'"
   " | " grep "/bin/grep -vE ' 0$'"
   " ||:"))
--8<---------------cut here---------------end--------------->8---

--8<---------------cut here---------------start------------->8---
           (cron-timer 'cron-btrfs-error-counts-root
                       "*/15 * * * *"
                       (script/btrfs-error-counts "/"))
--8<---------------cut here---------------end--------------->8---

Even regular access to the files will verify the checksum and increase
error counter when there is mismatch, so I prefer to be told (== receive
an email) when that happens.

>
> I'd also advise using just compress=zstd and not compress-force=zstd, as
> the later limits the size of Btrfs extents (if I recall the terminology
> right) created to 512 KiB or similar, leading to a huge number of
> extents over time, which can slow some things down such as mounting the
> file system at boot.
>
> In case you have any question, knowledgeable Btrfs folks are usually
> responsive in #btrfs on Libera.chat.
>
> Cheers!

Hope this will be useful,
Tomas

0: 
https://archive.kernel.org/oldwiki/btrfs.wiki.kernel.org/index.php/FAQ.html#Do_I_need_to_run_a_balance_regularly.3F
1: https://unix.stackexchange.com/a/409572
2: https://wolfsden.cz/blog/post/using-gnu-shepherd-timers-as-crons.html

-- 
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.

Attachment: signature.asc
Description: PGP signature

Reply via email to