TRIM and ubihealthd Support (Linux)
Introductionβ
ubihealthd
is a simple daemon that scans every PEB of a UBI device in random order. It helps to deal with read disturb on systems that either reboot infrequently, use UBI Fastmap or hardly read much data. This would prevent data loss for systems running unattended for quite a long time.
Modern eMMC and SSD storage devices require an ATA interface fstrim
command, and for this, an OS built on the Linux kernel provides two methods of management at the file system level:
- discard: installed as an option when mounting the filesystem. Allows the Linux kernel to immediately send a TRIM command to the device as soon as the filesystem reports it.
- fstrim: it is a utility that is launched manually or on a schedule as an OS service that sends a list of deleted blocks from the filesystem to clean them up low-level on the device.
This article complies with the Typographic Conventions for the Toradex Documentation.
Prerequisitesβ
- BSP Layers and Reference Images for Yocto Project 5.2.0 or newer.
- For
ubihealthd
: a Toradex SoM equipped with raw NAND (Colibri iMX6ULL 256MB/512MB, Colibri iMX7 256MB/512MB). - For
fstrim
: any Toradex SoM supported by BSP 5. - (optional) basic knowledge of systemd's services and timers.
ubihealthdβ
ubihealthd
is provided as part of ubi-utils
. It is only available for raw NAND-based Toradex SoMs, as they run the UBIFS filesystem. The BSP Layers and Reference Images for Yocto Project, starting from release 5.2.0, provides the ubihealthd.service
daemon.
ubi-utils
is not deployed to any eMMC modules running VFAT/ext4 instead of UBIFS. ubihealthd
must not be used on eMMC-based SKUs.
ubihealthd Serviceβ
The ubihealthd
service is disabled by default and you can configure it depending on your system-level use-case.
To enable the service on the board, making it automatically start on every boot:
# systemctl enable ubihealthd.service
Created symlink /etc/systemd/system/multi-user.target.wants/ubihealthd.service -> /lib/systemd/system/ubihealthd.service.
To start the service without rebooting:
# systemctl start ubihealthd.service
To check the system health, for example if it started successfully:
# systemctl status ubihealthd.service
* ubihealthd.service - UBI health daemon
Loaded: loaded (/lib/systemd/system/ubihealthd.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2021-07-20 12:10:43 UTC; 17s ago
Process: 635 ExecStart=/usr/sbin/ubihealthd -i 240 (code=exited, status=0/SUCCESS)
Main PID: 636 (ubihealthd)
Tasks: 1 (limit: 1023)
Memory: 272.0K
CGroup: /system.slice/ubihealthd.service
`-636 /usr/sbin/ubihealthd -i 240
Jul 20 12:10:43 colibri-imx6ull-06388146 systemd[1]: Starting UBI health daemon...
Jul 20 12:10:43 colibri-imx6ull-06388146 systemd[1]: Started UBI health daemon.
To enable the service in a custom image built the with Yocto Project/OpenEmbedded, you must set SYSTEMD_AUTO_ENABLE = "enable"
in the recipe meta-toradex-bsp-common/recipes-devtools/mtd/mtd-utils_%.bbappend.
ubihealthd Settingsβ
ubihealthd
provides command-line options, like the UBI device and an interval to rerun it:
# ubihealthd -help
Usage: ubihealthd [ -d UBI_DEVICE ] [-i INTERVAL_SEC ] [ -f ]
The default settings for these options are /dev/ubi0
for the UBI device and 120 seconds for the default interval. ubihealthd.service
is running with default settings. These settings can be modified with appropriate changes made in the /lib/systemd/system/ubihealthd.service on the device:
[Unit]
Description=UBI health daemon
After=multi-user.target
[Service]
Type=forking
ExecStart=/usr/sbin/ubihealthd
[Install]
WantedBy=multi-user.target
For example, to change the interval to 240 seconds, edit the line ExecStart
by adding the option -i 240
:
ExecStart=/usr/sbin/ubihealthd -i 240
Reload and restart the service, and check that it is running with the new parameter:
# systemctl daemon-reload
# systemctl restart ubihealthd.service
# ps aux | grep ubihealthd
root 651 0.0 0.0 1388 136 ? Ss 11:23 0:00 /usr/sbin/ubihealthd -i 240
To customize the settings on a custom image built the with Yocto Project/OpenEmbedded, edit the file meta-toradex-bsp-common/recipes-devtools/mtd/mtd-utils/ubihealthd.service. For example, to set the interval to 240 seconds, set ExecStart=@SBINDIR@/ubihealthd -i 240
.
fstrimβ
fstrim
is often run periodically. You can configure the systemd timer fstrim.timer
to execute the fstrim.service
periodically. By default, it runs the service weekly, every Monday 00:00:00.
fstrim Serviceβ
Enable and start the timer:
# systemctl enable fstrim.timer
Created symlink /etc/systemd/system/timers.target.wants/fstrim.timer -> /lib/systemd/system/.
# systemctl start fstrim.timer
Check that the timer is active, and when it is scheduled to run next:
# systemctl list-timers
NEXT LEFT LAST PASSED UNIT
Mon 2021-07-12 00:00:00 UTC 4 days left n/a n/a fstrim.timer
To enable the service in a custom image built the with Yocto Project/OpenEmbedded, you must set SYSTEMD_AUTO_ENABLE = "enable"
in the recipe meta-toradex-bsp-common/recipes-core/util-linux/util-linux_%.bbappend.
fstrim Settingsβ
To adjust the frequency of the fstrim.timer
, you must edit the lines OnCalendar=weekly
and AccuracySec=1h
on the file /lib/systemd/system/fstrim.timer:
[Unit]
Description=Discard unused blocks once a week
ConditionVirtualization=!container
[Timer]
OnCalendar=weekly
AccuracySec=1h
Persistent=true
[Install]
WantedBy=timers.target
To make a proper configuration, learn more about the systemd timer options and the syntax of calendar event expressions.
To customize the settings on a custom image built the with Yocto Project/OpenEmbedded, edit the file meta-toradex-bsp-common/recipes-core/util-linux/util-linux/fstrim.timer.
Check fstrim Supportβ
To check if TRIM is supported, run the following command:
# lsblk --discard
NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
mmcblk1 0 512B 3.5M 0
|-mmcblk1p1 0 512B 3.5M 0
`-mmcblk1p2 0 512B 3.5M 0
mmcblk1boot0 0 512B 3.5M 0
mmcblk1boot1 0 512B 3.5M 0
If you see zero values ββin the DISC-GRAN
(discard granularity) and DISC-MAX
(discard max bytes) columns on the SSD device, then TRIM is not working.
With full TRIM support, the values ββshould be shown on all partitions, as in the example above. DISC-GRAN is 512B because the sector size on the storage device is 512 bytes. The operating system sends a TRIM command to the drive controller specifying the sector numbers that can be cleared.
Alternatively, you can also check with the manual TRIM command:
# fstrim -v /
2/: 2.7 GiB (2917261312 bytes) trimmed
If you see a positive result, then TRIM is working.