Enable TRIM on external LUKS encrypted drive

If you use an encrypted external SSD, you should periodically trim it. The first step would be to make sure the external drive itself supports trimming. The next step would be to make sure the LUKS partition on the device supports trimming as well. By default, encrypted filesystems do not support passing discard requests due to some security concerns. For example, crypttab man page states:

WARNING: Assess the specific security risks carefully before enabling this option. For example, allowing discards on encrypted devices may lead to the leak of information about the ciphertext device (filesystem type, used space etc.) if the discarded blocks can be located easily on the device later.

For most users, the benefit of TRIM outweigh those security concerns. The easiest way to enable TRIM is to pass the dicard option in /etc/crypttab. For example:

cdisk0 UUID=12345678-9abc-def012345-6789abcdef01 none luks,discard

The problem with the /etc/crypttab approach is that it requires you to pre-configure your external drives. A better approach would be to enable discards at the LUKS configuration, which would apply automatically whenever the drive is used. This can be done in LUKS version 2 headers.

# cryptsetup --allow-discards --persistent refresh luks-643dc0f7-c876-4e37-9207-5c053a75fc70

Where luks-643dc0f7-c876-4e37-9207-5c053a75fc70 is the name of the mapping for the encrypted drive. You can verify that allow_discards is now part of the flag by dumping the LUKS header.

# cryptsetup luksDump /dev/sda4 | grep Flags
Flags:       	allow-discard

Now, you should be able to use fstrim to trim your external SSD with LUKS encryption drive.

Enable TRIM/discard on external SSD

First, find out whether your device already supports TRIM commands.

$ lsblk --discard

Non-zero values in the DISC-GRAN and DISC-MAX indicate support. If it looks like your external SSD doesn’t support trimming, then maybe it supports UNMAP which is equivalent (UNMAP is just in the SCSI command set vs TRIM which is in the ATA command set). Assuming your external drive is /dev/sda

# apt install sg3-utils
# sg_vpd -a /dev/sda | grep -i unmap

If the last command has Unmap command supported (LBPU): 1 it means the drive supports the UNMAP command. If it’s supported, and discard wasn’t supported, it’s likely the kernel didn’t detect the UNMAP support. You can verify it by reading /sys/block/sda/device/scsi_disk/0\:0\:0\:0/provisioning_mode

$ cat /sys/block/sda/device/scsi_disk/0\:0\:0\:0/provisioning_mode 
full

full means no support. As we know our device supports unmap we can manually instruct the kernel about it.

# echo "unmap" >/sys/block/sda/device/scsi_disk/0\:0\:0\:0/provisioning_mode 

Now, lsblk --discard should report that the drive supports trimming, and you can use fstrim to trim it.

Making the change permanent

The changes above are ephemeral and will be reverted once you disconnect the drive. If you want to automatically apply those changes whenever your external drive is connected, we need to use udev rules.

Add the following rule to udev under /etc/udev/rules.d/90-usb-discard.rules

ACTION=="add|change", ATTRS{idVendor}=="0b05", ATTRS{idProduct}=="1932", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap"

Replace idVendor and idProduct above with the corresponding values for your device, as can be found in the output of lsusb.

Reload the udev rules using

# udevadm control --reload