ZFS scrub and trim

From Alpine Linux
Revision as of 21:39, 24 August 2023 by Dju92 (talk | contribs) (Created page with "= Introduction = On alpine linux, there in no cron/script provided to scrub (and eventually trim) your pool(s) on a regular basis, like in other linux distributions.<br> Setting it up is easy and can be done in a few minutes. = Scrub = == Definition == {{Note|The scrub examines all data in the specified pools to verify that it checksums correctly. For replicated (mirror, raidz, or draid) devices, ZFS automatically repairs any damage discovered during the scrub<br> Wh...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Introduction

On alpine linux, there in no cron/script provided to scrub (and eventually trim) your pool(s) on a regular basis, like in other linux distributions.
Setting it up is easy and can be done in a few minutes.

Scrub

Definition

Note: The scrub examines all data in the specified pools to verify that it checksums correctly. For replicated (mirror, raidz, or draid) devices, ZFS automatically repairs any damage discovered during the scrub

When scrubbing a pool with encrypted filesystems the keys do not need to be loaded. However, if the keys are not loaded and an unrepairable checksum error is detected the file name cannot be included in the zpool status -v verbose error report.

A scrub is split into two parts: metadata scanning and block scrubbing. The metadata scanning sorts blocks into large sequential ranges which can then be read much more efficiently from disk when issuing the scrub I/O.

Creating the script

This script is used to list the pools, make sure they are online, and no scrub is being done at the time.
We will write it in /usr/libexec/zfs/scrub
It's taken from debian zfs scripts

#!/bin/sh -eu

# directly exit successfully when zfs module is not loaded
if ! [ -d /sys/module/zfs ]; then
        exit 0
fi

# [auto] / enable / disable
PROPERTY_NAME="org.alpine:periodic-scrub"

get_property () {
        # Detect the ${PROPERTY_NAME} property on a given pool.
        # We are abusing user-defined properties on the root dataset,
        # since they're not available on pools https://github.com/openzfs/zfs/pull/11680
        # TODO: use zpool user-defined property when such feature is available.
        pool="$1"
        zfs get -H -o value "${PROPERTY_NAME}" "${pool}" 2>/dev/null || return 1
}

scrub_if_not_scrub_in_progress () {
        pool="$1"
        if ! zpool status "${pool}" | grep -q "scrub in progress"; then
                # Ignore errors and continue with scrubbing other pools.
                zpool scrub "${pool}" || true
        fi
}

# Scrub all healthy pools that are not already scrubbing as per their configs.
zpool list -H -o health,name 2>&1 | \
        awk -F'\t' '$1 == "ONLINE" {print $2}' | \
while read pool
do
        # read user-defined config
        ret=$(get_property "${pool}")
        if [ $? -ne 0 ] || [ "disable" = "${ret}" ]; then
                :
        elif [ "-" = "${ret}" ] || [ "auto" = "${ret}" ] || [ "enable" = "${ret}" ]; then
                scrub_if_not_scrub_in_progress "${pool}"
        else
                cat > /dev/stderr <<EOF
$0: [WARNING] illegal value "${ret}" for property "${PROPERTY_NAME}" of ZFS dataset "${pool}".
$0: Acceptable choices for this property are: auto, enable, disable. The default is auto.
EOF
        fi
done

Then make the script executable

# chmod +x /usr/libexec/zfs/script

Launching the scrub script with cron

It is recommanded to launch a scrub regularly to assure your pool(s) and datas are in good shape.
Here, the scrub will be launched once a month, on the 2nd sunday of the month.

In root, edit your crontabs

# crontab -e

and add these 2 lines

# zfs scrub the second sunday of every month
24      0       8-14    *       *       if [ $(date +\%w) -eq 0 ] && [ -x /usr/libexec/zfs/scrub ]; then /usr/libexec/zfs/scrub; fi

Finally, make sure cron is launched:

# rc-update

There should be a ligne saying

crond |      default

If not, add it to the boot sequence

# rc-update add crond

then start the crond daemon

# rc-service crond start

Trim