Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

You can easily check if TRIM works for a "normal" ext4 partition: http://askubuntu.com/a/19480/5920.

How to do that for a LUKS-encrypted one? Let's assume the default LUKS setup made by 12.04 Alternate installer (i.e. the one with LVM involved).

Update

What I'm asking here is how I can check that the block on the disk is actually filled with zeros after removing the file, if the file is stored in an encrypted volume.

share|improve this question

4 Answers 4

I don't have dm-crypt with TRIM setup yet, but I'm also interested in verifying this. First it should be said that this might not be possible, depending on your SSD (see: http://serverfault.com/a/401506/60525).

Assuming you have the right kind of SSD, I see a couple different options:

  1. Test this on a very small block device. Create a 20Mb encrypted partition just as you would for your whole system. Make sure to first fill the partition with random bytes. Then create, write, flush, and delete a 10Mb file on the encrypted fs. Run fstrim on the mounted fs. If everything is working, you should see about half the 20Mb partition filled with zero bytes.

  2. Alternatively you could verify that either the UNMAP or WRITE SAME scsi command is being issued through the scsi subsystem. The only way that I found to see the scsi packets without using a hardware device or hacking the kernel was to turn on logging of scsi packets:

    echo $BITMASK > /sys/module/scsi_mod/parameters/scsi_logging_level

    Using 9216 as the BITMASK was enough for me to see WRITE SAME cdbs being send after an fstrim of an ext4 fs residing directly on disk (no encryption).

    You could use either fstrim at the fs level or sg_unmap/sg_write_same at the device level to trigger a TRIM. Once you find either UNMAP or WRITE SAME, use the scsi docs at t10.org to decode the packet and figure out what disk block its referring to. Then check that the disk has all zeroes at that sector(s).

The latter approach is more arduous, but it has the advantage of working on pre-existing installs and is much easier when working with non-trivially sized filesystems. You may find it sufficient to see the UNMAP or WRITE SAME command being sent (do you really care if there are zeros or not?) Note that the latter approach will likely not work if the TRIM is done via the ata DATA SET MANAGEMENT command, it shouldn't show up in the scsi log and I see not way to get ata cdbs. But I'd bet that's less than .01% of the cases.

The latter solution could be some what automated, that way we wouldn't have to decode the packet by hand. Any takers?

And as far as I now there's no way to get a mapping of encrypted block address to device block address without hacking dm-crypt.c So if you're looking to see that the blocks of a deleted file on a trimmed fs on the encrypted block device map to zero sectors on the device, you're in for a world of pain.

share|improve this answer
    
Interesting ideas! I'll try them when I have some time to spend :) –  Tomasz Zieliński Aug 9 '12 at 8:42

This was answered in the question you linked.

If you are using LVM, you need to add discard to the options in /etc/fstab

Open /etc/fstab with any editor

# Command line
sudo -e /etc/fstab

# Graphical
gksu gedit /etc/fstab

Add in "discard" to the options in the 4th column.

/dev/mapper/volumegroup-root  /  ext4  discard,noatime,nodiratime,errors=remount-ro  0  1

You then add in the same option (discard) to /etc/crypttab

Assuming your LUKS partition is /dev/sda1 (adjust accordingly)

# Command line
sudo -e /etc/crypttab

# Graphical
gksu gedit /etc/crypttab

Again, add in discard:

sda1_crypt UUID=[... series of numbers ...] none luks,discard

Update your initramfs

sudo update-initramfs -c -k all

Reboot

Confirm TRIM is working ...

sudo dmsetup table /dev/mapper/sda1_crypt --showkeys

You should see "allow_discards" in the output

For additional information, see : http://worldsmostsecret.blogspot.com/2012/04/how-to-activate-trim-on-luks-encrypted.html

share|improve this answer
    
Thanks for the answers, but I meant a different thing in my question, sorry for the lack of clarification. Check my updated question. FYI sudo dmsetup table /dev/mapper/sda1_crypt --showkeys returns allow_discards, but I'd like to check if the disk is actually TRIM-ed. –  Tomasz Zieliński Jul 11 '12 at 18:17

I don't see how TRIM can work at all for an encrypted volume ; the volume is, by definition, full of random-looking (ie - non zero) data. TRIM zeroes blocks when the file system no longer has active data stored on them. In an encrypted volume, what is stored on the hardware block device is not a file system, but a virtual block device.

share|improve this answer
1  
Well, it works. But I'd like to see those zeros myself :) –  Tomasz Zieliński Jul 11 '12 at 18:18

There is a way to test it answered at unix.stackexchange.com by frostschutz (this answer is his merit so thanks him), copied below:

"Create a test file: (not random on purpose)

# yes | dd iflag=fullblock bs=1M count=1 of=trim.test 

Get the address: (exact command may have to differ depending on filefrag version)

# filefrag -s -v trim.test
File size of trim.test is 1048576 (256 blocks, blocksize 4096)
 ext logical physical expected length flags
   0       0    34048             256 eof
trim.test: 1 extent found

Get the device:

# df trim.test
/dev/mapper/something  32896880 11722824  20838512   37% /

With this set up, you have a file trim.test filles with yes-pattern on /dev/mapper/something at address 34048 with length of 256 blocks of 4096 bytes.

Reading that from the device directly should produce the yes-pattern:

# dd bs=4096 skip=34048 count=256 if=/dev/mapper/something | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
00100000

If TRIM is enabled, this pattern should change when you delete the file. Note that caches need to be dropped also, otherwise dd will not re-read the data from disk.

# rm trim.test
# sync
# fstrim -v /mount/point/ # when not using 'discard' mount option
# echo 1 > /proc/sys/vm/drop_caches
# dd bs=4096 skip=34048 count=256 if=/dev/mapper/something | hexdump -C

On most SSD that would result in a zero pattern:

00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000

If encryption is involved, you will see a random pattern instead:

00000000  1f c9 55 7d 07 15 00 d1  4a 1c 41 1a 43 84 15 c0  |..U}....J.A.C...|
00000010  24 35 37 fe 05 f7 43 93  1e f4 3c cc d8 83 44 ad  |$57...C...<...D.|
00000020  46 80 c2 26 13 06 dc 20  7e 22 e4 94 21 7c 8b 2c  |F..&... ~"..!|.,|

That's because physically trimmed, the crypto layer reads zeroes and decrypts those zeroes to "random" data.

If the yes-pattern persists, most likely no trimming has been done."


This is my automated script:

#!/bin/bash
#
# This script is provided "as is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement.
#
# License GPL2
#
# by desgua 2014/04/29

function CLEAN {
cd "$pasta"
[ -f test-trim-by-desgua ] && rm test-trim-by-desgua && echo "Temp file removed"
echo "Goodbye"
exit 0
}

trap 'echo ; echo "Aborted." ; CLEAN; echo ; exit 0' INT HUP

if [[ "$(echo $USER)" != "root" ]]; then

read -n 1 -p 'Become root? [Y/n]' a
    if [[ $a == "Y" || $a == "y" || $a == "" ]]; then
        sudo $0 $1
        exit 0
    else
        echo "
        This script needs root privilege.
        "
        exit 1

    fi

fi


name=$(echo $0 | sed 's/.*\///')
if [ $# -ne 1 ]; then

echo "
Usage: $name /folder/to/test/

"
exit 1
fi

pasta=$1

read -n 1 -p 'Use fstrim? [y/N]' a
if [[ $a == "Y" || $a == "y" ]]; then
    fs=1
fi

method=
while [[ "$method" != "1" && "$method" != "2" ]]; do
read -n 1 -s -p 'Choose a method:
[1] hdparm (will fail in LUKS on LVM)
[2] filefrag (warning: you may have to force quit - close the terminal - in some cases of success trim if you see an output that never ends) 
' method
done

function SDATEST {
disk=$(fdisk -l | grep /dev/sda)
if [ "$disk" == "" ]; then
echo "
fdisk did not found /dev/sda 
"
exit 1
fi
}

function TEST {
echo "Entrying /" ; echo
cd $pasta
echo "Creating the file test-trim-by-desgua at $pasta" ; echo
dd if=/dev/urandom of=test-trim-by-desgua count=10 bs=512k
echo "Syncing and sleeping 2 seconds." ; echo
sync
sleep 2

hdparm --fibmap test-trim-by-desgua
lbab=$(hdparm --fibmap test-trim-by-desgua | tail -n1 | awk '{ print $2 }')

echo "As you can see, the file was created and its LBA begins at $lbab" ; echo

echo "Syncing and sleeping 2 seconds." ; echo
sync
sleep 2

echo "Removing file test-trim-by-desgua" ; echo 
rm test-trim-by-desgua

trap 'echo ; echo ; echo "Aborted." ; echo ; exit 0' INT
echo "Syncing and sleeping 2 seconds." ; echo
sync
sleep 2

if [[ "$fs" == "1" ]]; then 
    echo "fstrim $pasta && sleep 2" ; echo
    fstrim $pasta
    sleep 2
fi

echo "This is readed from sector $lbab: "
hdparm --read-sector $lbab /dev/sda

pass=$(hdparm --read-sector $lbab /dev/sda | grep "0000 0000 0000 0000")

if [[ $pass == "" ]]; then
    echo "
Trim failed... 
You should see only 0000 0000 0000 0000 ...
"
else
    echo "Success!!!"
fi
exit 0

}

function LUKSTEST {
# Reference: http://unix.stackexchange.com/questions/85865/trim-with-lvm-and-dm-crypt#
echo 1 > /proc/sys/vm/drop_caches
cd $pasta
echo "Creating a \"yes\" file."
yes | dd iflag=fullblock bs=1M count=1 of=test-trim-by-desgua

#position=`filefrag -s -v test-trim-by-desgua | grep "eof" | awk '{ print $3 }'`
position=`filefrag -s -v test-trim-by-desgua | grep "eof" | sed 's| ||g ; s|.*255:|| ; s|\.\..*||'`
[[ "$position" == "" ]] && echo "Could not find the position of the file. Are you on a LUKS on LVM?" && CLEAN;

device=`df test-trim-by-desgua | grep "dev/" | awk '{ print $1 }'`

yes=`dd bs=4096 skip=$position count=256 if=$device | hexdump -C`

echo "In the next line you should see a pattern like: 
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
$yes
"

if [[ "`echo "$yes" | grep "y.y.y"`" == "" ]]; then 
    echo "The pattern could not be checked. Something went wrong. Exiting."
    CLEAN;
else
    echo "Pattern confirmed."
fi

echo "Removing the temp file." 
rm test-trim-by-desgua

echo "Syncing."
sync
sleep 1

if [[ "$fs" == "1" ]]; then 
    echo "fstrim -v $pasta && sleep 2" ; echo
    fstrim -v $pasta
    sleep 2
fi

# Drop cache
echo 1 > /proc/sys/vm/drop_caches

echo "In the next line you should **NOT** see a yes pattern like: 
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.| 
If you see, then trim is not working:
`dd bs=4096 skip=$position count=256 if=$device | hexdump -C`"

yes=`dd bs=4096 skip=$position count=256 if=$device | hexdump -C`
if [[ "`echo "$yes" | grep "y.y.y"`" != "" ]]; then 
    echo "TRIM not working."
else
    echo "TRIM is working!"
fi
CLEAN;
}

if [[ "$method" == "1" ]]; then
    SDATEST;
    TEST;
elif [[ "$method" == "2" ]]; then
    LUKSTEST;
fi
exit 0
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.