#!/bin/bash
# Purpose of this script:
# perform fstrim -av every 4-8 hours, preferably when disk is idle
# Installation:
# ---------------
# - Put it to /usr/local/bin/SSDidletrim.sh
# - Set the Permissons sudo chmod 744 /usr/local/bin/SSDidletrim.sh
# - Startup: we put a new line in /etc/rc.local for systemwide start.
# /usr/local/bin/SSDidletrim.sh & >/dev/null
# exit 0
#
# Now you can reboot the pc, for activate or to activate a change.
# # **************************************************
##################################################
### troubleshooting ###
# please check your PATH settings if you run into problems, also make sure your script is executing with root permissions
# especially when using crontab, it may happen, that the path settings differ from what you expect.
# so you should test under real conditions, to be sure its working
#
### check the followung commands are working
# cat /proc/diskstats
# sudo fstrim -av
#
### logfile watching
# watch "cat /var/log/SSDidletrim.log && echo --- && ps -ef | grep -i SSDidletrim | grep -ivw grep"
##################################################
### Logfile:
SSDidletrimLog="/var/log/SSDidletrim.log"
# Where is your Ramdrive?
# Check it out with df -h or mount command.
# Possible Values Examples: /dev/shm , /run/shm
#ramdrive=/run/shm
ramdrive=/var/tmp
# The SSD trim Time in Seconds
# The Raktion done in $SSDtrimtime maximum of 2 times. Depending build by the script. Protects for the cpu load.
let SSDtrimtimeInit=4*3600;
if [ $1 ] ; then let SSDtrimtimeInit="$1"; fi
let SSDtrimtime=$SSDtrimtimeInit;
# Counter
# counter, 0 means infinite
let counter=0;
if [ $2 ] ; then let counter="$2"; fi
# Log
# appendlog= append log, newlog=new log (default), nolog= no output to logfile
logmode="newlog";
if [ $3 ] ; then logmode="$3"; fi
if [ "$logmode" == "nolog" ]; then SSDidletrimLog="/dev/null"; fi #!!caution!! stringcompare spaces: if_[_$1_==_ $2_]; then usw.
if [ "$logmode" == "newlog" ]; then rm $SSDidletrimLog; fi
# Which disks are handled
diskvolumes="a b c d e f g h i j k l m n o p q r s t u v w x y z"
#watch "date && cat /proc/diskstats | grep sd"
# Build onece the tempfiles
if [ ! -f $ramdrive/ssddiskstate1 ]; then touch $ramdrive/ssddiskstate1;fi
if [ ! -f $ramdrive/ssddiskstate2 ]; then touch $ramdrive/ssddiskstate2;fi
###
#Wait before 1st run and initialize file ssddiskstate1
#Start logging
echo '***'
echo start disk monitoring: SSDidletrim.sh - ssd trim when idle
echo start disk monitoring: SSDidletrim.sh - ssd trim when idle >> $SSDidletrimLog
echo "date: $(date) --- settings: "seconds:$SSDtrimtime repeat:$counter "
echo "date: $(date) --- settings: "seconds:$SSDtrimtime repeat:$counter " >> $SSDidletrimLog
echo '************************************************************************ '
echo '* usage: sudo [/bin/bash] SSDidletrim.sh [ <delay> [ <count> [ [newlog|appendlog|nolog] ] ] ] '
echo '* example: sudo /usr/local/bin/SSDidletrim.sh 9 9 >/dev/null & # trim after 9/4/2/1 seconds, 9 rounds'
echo "* view log: cat /var/log/SSDidletrim.log"
echo '************************************************************************ '
echo '*** ps -ef | grep -i SSDidletrim | grep -ivw grep ***'
ps -ef | grep -i SSDidletrim | grep -ivw grep
echo '*** ps -ef | grep -i SSDidletrim | grep -ivw grep ***' >> $SSDidletrimLog
ps -ef | grep -i SSDidletrim | grep -ivw grep >> $SSDidletrimLog
echo '****************************************************************'
# Here we go...
cat /proc/diskstats > $ramdrive/ssddiskstate1
#let SSDtrimtime=1; # on the first run perform trim without delay
let count=0;
let shutdown=0;
while [ true ] ; do
sleep 1; #wait 1 sec min between every loop
# cycle diskstat to test for activity
mv $ramdrive/ssddiskstate1 $ramdrive/ssddiskstate2
cat /proc/diskstats > $ramdrive/ssddiskstate1
# Loop through all array disks and spin down idle disks.
let allidle=1;
for disk in $diskvolumes
do
if [ "$(diff $ramdrive/ssddiskstate1 $ramdrive/ssddiskstate2 | grep -w sd$disk )" = "" ] ; then
# skip drive letters that are currently not used
if [ $(cat $ramdrive/ssddiskstate1 | grep -cw -m 1 sd$disk ) != "0" ] ; then
#-hdparm -y /dev/sd$disk >/dev/null 2>&1;
#echo hdparm -y /dev/sd$disk
#echo hdparm -C /dev/"sd$disk"
# removed: echo $(hdparm -C /dev/"sd$disk" 2> /dev/null | grep "sd$disk" -A 1)
# removed: echo $(hdparm -C /dev/"sd$disk" 2> /dev/null| grep "sd$disk" -A 1) >> $SSDidletrimLog
#-echo spindown "sd$disk"
#-echo spindown "sd$disk" >> $SSDidletrimLog
: # simply empty command
fi;
else
let allidle=0;
fi;
done
let count+=1;
if [ "$counter" -eq "$count" ]; then break; fi
if [ $((count % 999)) -eq 0 ]; then rm $SSDidletrimLog; echo remove; fi # simple logfile size limit
if [ $allidle -eq 1 ] ; then
let allidlecount=$allidlecount+1;
else
let allidlecount=0;
fi;
if [ $allidle -eq 1 -o $SSDtrimtime -lt 2 ] ; then
#trimresult=$(sudo fstrim -av)
echo --- trim interval $SSDtrimtime --- | tee -a $SSDidletrimLog
sudo fstrim -av | tee -a $SSDidletrimLog
echo startloop':' SSDtrimtimeInit $SSDtrimtimeInit // date $(date) | tee -a $SSDidletrimLog
let SSDtrimtime=$SSDtrimtimeInit;
else
let SSDtrimtime=$SSDtrimtime/2;
fi;
echo trimtime $SSDtrimtime count $count
#test only
##check networkactivity 1 sec
#nwstat=($(dstat -n --bw 1 1 | grep -v e)); let nwaktiv=0; for ele in "${nwstat[@]}"; do if [ $ele != "0" ]; then let nwaktiv+=1 ;fi ; done ;
#for ele in "${nwstat[@]}"; do echo $i $ele; let i+=1; done
#echo nwaktiv $nwaktiv
#if [ $nwaktiv -ge 1 ] ; then
# allidlecount=0;
#fi
#Wait
sleep $SSDtrimtime
done
echo script finished':' $0
exit 0
#Beta release 2.3.2020