Let’s be clear from the begining.

This entire article applies to Linux virtual machines.

In Windows, the process described below — reclaiming space using TRIM — is usually automated. The operating system collaborates with the SSD or underlying storage and automatically notifies it about freed blocks.

The problem

So, you’re on Linux. You’ve deleted a large number of files (see the example with MinIO object deletion).
If you run df -h inside the VM, you’ll notice that free space has increased significantly.
However, on the VMware datastore or the underlying physical storage, nothing has changed.

Why is that?

Why is This Happening?

When you delete files, the Linux filesystem (ext4, XFS, etc.) simply marks those files as deleted. The actual data blocks remain untouched on disk — they are just marked as free within the guest OS.

These changes are not automatically visible to the VMware datastore or to the physical storage layer.

If your LUN is thin-provisioned, and your storage system supports SCSI UNMAP, TRIM, or space reclamation, then the operating system must explicitly notify the storage that those blocks can be reclaimed.

Step 1: Verify if Your Disk Supports TRIM

To check if your virtual disk supports TRIM (also known as UNMAP), run the following command: lsblk -D

You’ll get output similar to this:

[root@minio-prod-01 ~]# lsblk -D
NAME        DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
sda                0        1M      32M         0
├─sda1             0        1M      32M         0
├─sda2             0        1M      32M         0
└─sda3             0        1M      32M         0
  ├─rl-root        0        1M      32M         0
  ├─rl-swap        0        1M      32M         0
  └─rl-home        0        1M      32M         0
sdb                0        1M      32M         0
sdc                0        1M      32M         0
sdd                0        1M      32M         0
sde                0        1M      32M         0
sdf                0        1M      32M         0
sdg                0        1M      32M         0
sdh                0        1M      32M         0
sdi                0        1M      32M         0
sr0                0        0B       0B         0
[root@minio-prod-01 ~]#

Focus on the DISC-GRAN and DISC-MAX columns.

  • If both are non-zero, it means TRIM/UNMAP is supported by the device.
  • In this example, DISC-GRAN is 1M and DISC-MAX is 32M, which confirms support for TRIM.

Step 2: Apply TRIM

There are two common ways to perform TRIM operations on a Linux VM.

Method 1 – Real-Time TRIM via discard Option

You can enable TRIM in real time by adding the discard mount option in /etc/fstab.

Example:

/dev/sdb  /mnt/disk1  xfs  defaults,discard  0  0

⚠️ Note: Using discard enables real-time TRIM, but may introduce a slight performance overhead.
For large volumes of data, it’s generally recommended to run TRIM manually on a schedule — see Method 2 below.

Method 2 – Scheduled TRIM Using fstrim

You can manually trigger TRIM for a mounted disk using the fstrim command:

Example:

[root@minio-prod-01 ~]# fstrim -v /mnt/disk1
/mnt/disk1: 76.1 GiB (81664561152 bytes) trimmed
[root@minio-prod-01 ~]#

To trim multiple disks at once, use a simple loop:

for i in {1..8}; do
  echo "Trimming /mnt/disk$i"
  fstrim -v /mnt/disk$i
done

Automating with Cron

The most robust approach is to automate this process via cron. Below is a script that trims all mounted disks (/mnt/disk1 to /mnt/disk8) and logs the results in /var/log/minio-trim/.

Create the daily cron script:

cat <<'EOF' > /etc/cron.daily/minio-trim
#!/bin/bash

LOGDIR="/var/log/minio-trim"
LOGFILE="$LOGDIR/$(date +%F).log"

mkdir -p "$LOGDIR"

echo "=== fstrim started at $(date) ===" >> "$LOGFILE"

for disk in /mnt/disk{1..8}; do
  if mountpoint -q "$disk"; then
    echo "Trimming $disk..." >> "$LOGFILE"
    fstrim -v "$disk" >> "$LOGFILE" 2>&1
  else
    echo "Skipping $disk (not mounted)" >> "$LOGFILE"
  fi
done

echo "=== fstrim finished at $(date) ===" >> "$LOGFILE"
echo "" >> "$LOGFILE"
EOF

chmod +x /etc/cron.daily/minio-trim

Optional: Clean Up Old Logs

You can also create a second cron task to rotate logs and delete any older than 60 days:

cat <<'EOF' > /etc/cron.daily/minio-trim-logrotate
#!/bin/bash
find /var/log/minio-trim/ -type f -name "*.log" -mtime +60 -delete
EOF

chmod +x /etc/cron.daily/minio-trim-logrotate

Bonus! Configure Everything Using an RPM Package

If you manage multiple servers, repeating the same setup manually on each one can be tedious. A more efficient approach is to build a custom RPM package and deploy it across all servers.

1. Install Required Tools

dnf install rpm-build rpmdevtools -y

2. Set Up RPM Build Structure

rpmdev-setuptree

This creates the standard directory structure under ~/rpmbuild.

3. Create the .spec file

cat > ~/rpmbuild/SPECS/minio-trim.spec <<'EOF'
Name:           minio-trim
Version:        1.0
Release:        1%{?dist}
Summary:        Daily fstrim for MinIO volumes with logging and log rotation

License:        MIT
BuildArch:      noarch

%description
Runs daily fstrim on /mnt/disk1 to /mnt/disk8 for MinIO, logs output to /var/log/minio-trim/, and removes logs older than 30 days.

%prep

%build

%install
mkdir -p %{buildroot}/etc/cron.daily
mkdir -p %{buildroot}/var/log/minio-trim

cat > %{buildroot}/etc/cron.daily/minio-trim << 'EOS'
#!/bin/bash

LOGDIR="/var/log/minio-trim"
LOGFILE="$LOGDIR/$(date +%F).log"

mkdir -p "$LOGDIR"

echo "=== fstrim started at $(date) ===" >> "$LOGFILE"

for disk in /mnt/disk{1..8}; do
  if mountpoint -q "$disk"; then
    echo "Trimming $disk..." >> "$LOGFILE"
    fstrim -v "$disk" >> "$LOGFILE" 2>&1
  else
    echo "Skipping $disk (not mounted)" >> "$LOGFILE"
  fi
done

echo "=== fstrim finished at $(date) ===" >> "$LOGFILE"
echo "" >> "$LOGFILE"
EOS

chmod 0755 %{buildroot}/etc/cron.daily/minio-trim

cat > %{buildroot}/etc/cron.daily/minio-trim-logrotate << 'EOS'
#!/bin/bash
find /var/log/minio-trim/ -type f -name "*.log" -mtime +30 -delete
EOS

chmod 0755 %{buildroot}/etc/cron.daily/minio-trim-logrotate

%files
%attr(0755,root,root) /etc/cron.daily/minio-trim
%attr(0755,root,root) /etc/cron.daily/minio-trim-logrotate
%dir %attr(0755,root,root) /var/log/minio-trim

%changelog
* Fri Aug 01 2025 You <[email protected]> - 1.0-1
- Initial version with daily trim and log cleanup
EOF

4. Build the RPM Package

rpmbuild -ba ~/rpmbuild/SPECS/minio-trim.spec

The resulting .rpm file will be located at ~/rpmbuild/RPMS/noarch/minio-trim-1.0-1.noarch.rpm

5. Install the RPM on All Target Servers

dnf install minio-trim-1.0-1.noarch.rpm

✅ That’s it! You’ve now automated the entire TRIM and cleanup process across all your MinIO servers using a single, reusable package.

One Comment

Leave a Reply