Anyone have any ideas for how I can automatically do a luksSuspend
on a luks volume after it's been unused for a certain amount of time. I was thinking of just scheduling a command with crontab
or something, but I don't want it to suspend if I'm actually using the volume.
3 Answers
The intent of luksSetup
is to be used when the device is still in use, but you want to temporarily lock all accesses to it until the passphrase is entered from an external source. Thus it doesn't make much sense to only call luksSetup
when the device is unused: if it's unused, close it with luksClose
.
There's no way to atomically enforce that the device is not in use and call luksSuspend
. What you can do if you really want to suspend the device but only if it isn't in use is call luksSuspend
, then check with fuser
or lsof
for any mounted file on the filesystem that's on the encrypted device; if the filesystem is in use, call luksResume
immediately. That does have a small chance of requiring you to enter the passphrase.
To detect whether a filesystem is idle, I recommend to piggyback on an existing automounter such as autofs.
I've worked out a set of scripts that are working reasonably well, but still looking for other suggestions if anyone has any.
What I've done is to write one script that suspends the luks volume, one that sends a wall
message, alerting all users (at terminals) that it's about to be suspended, and one that tells it to keep it open (by writing to a file at a reserved path in /var/run
). I used cron to run the auto-suspend script every half hour, and the "alert" script 2 minutes before that (it only issues the alert if the volume is actually open). If anyone is interested in these scripts, I can post them, or at least more details about them.
I suggest using lsof
to determine if there are any running processes and passing the PIDs to pidstat
to analyze IO. From there, we will know whether or not it is safe and desirable to suspend based on what if any processes are accessing the LUKS volume's underlying filesystem.
This would allow you to confidently schedule the script without worry of corruption or processes handling the suspend in an unexpected manner.
#!/bin/bash
if [ ! $1 ] ; then
echo "Usage: $0 device-path"
exit 1
fi
DEVICE=$1
# Collect PIDs that are running on LUKS filesystem
pids=$(lsof $DEVICE | tail -n+2 | awk '{ print $2 }')
SUSPEND=1
if [ "$pids" ] ; then
# Get the IO statistics of each process running from LUKS device
pidactivity=$(echo -E "$pids" | tr "\n" "," | xargs pidstat -d -p)
# Pull out only the IO fields of the pidstat response
pidio=$(echo -E "$pidactivity" | tail -n+4 | awk '{ print $5 " " $6 }')
# If there is IO going on for any of these PIDs, we should suspend
for io in "$pidio" ; do
for stat in $io ; do
if [ `echo "$stat > 0" | bc` -gt 0 ] ; then
SUSPEND=0
break 2
fi
done
done
fi
if [ $SUSPEND -eq 1 ] ; then
cryptsetup luksSuspend $DEVICE
fi