Minimizing disk activity on linux
One common task I have had recently is to minimize the disk usage on a Ubuntu linux install. The reason why I want to do this is to prolong the life of the storage device. In my case Ubuntu is installed on a microSD card.
All of this applies to almost any modern linux distribution.
Filesystem mount options
By default, the ext4 filesystem records the access time of files on the filesystem. I see no reason to record this information. It's common to disable it in most circumstances.
You can edit /etc/fstab
as root in order to disable this feature. The file has 1 line per filesystem mounted. The line you are looking for looks like this
UUID=b22312e6-a495-4a5b-959f-4d73ec97e9bf / ext4 errors=remount-ro 0 1
The first item on the line identifies the filesystem, the second the mount point, the third the filesystem type, and the fourth is the options.
You can safely change the fourth item to update the mount options to look more like this. The UUID is unique for the filesystem you are running on.
UUID=b22312e6-a495-4a5b-959f-4d73ec97e9bf / ext4 discard,noatime,nodiratime,errors=remount-ro 0 1
I added the following
discard
- tell the underlying device to discard blocks. This has no effect if the device does not support itnoatime
- do not record the access time of filenodiratime
- do not record the directory access time
After you've made the change, you can apply the change immediately by running sudo mount -o remount /
in a shell. This remounts the filesystem and lets you know that you have the options set correctly in /etc/fstab
.
Reconfigure journalD
journalD is the component of systemd that is responsible for recording all the system logs. Logs are normally stored to disk. If you don't need your logs persisted you can save wear and tear on your storage device.
Volatile storage
To use only volatile storage, you need to edit /etc/systemd/journald.conf
and find the [Journal]
section. It is usually the only section in the configuration file.
The first value is to set Storage=volatile
. This tells systemd that all the storage to be used is in memory.
The next value is RuntimeMaxUse=128m
. This tells systemd how much memory to use to store logs. You can set it to whatever you like, depending on how much system memory you have.
Disable forwarding to syslog
journalD normally forwards all the logs to the syslog file as well. This obviously uses the storage device. So you can set ForwardToSyslog=no
in the /etc/systemd/journald.conf
to disable this behavior.
Some logs are still written to syslog, but the normal system service logs are no longer written to syslog in this case.
journald.conf example
This is what my entire /etc/systemd/journald.conf
file looks like now
[Journal] Storage=volatile RuntimeMaxUse=128M ForwardToSyslog=no
Restart journalD
To apply the above changes, run the command sudo systemctl restart systemd-journald
in a shell.
Clean out old logs
Since systemd was running with persistent storage in the past, it still has those logs in file somewhere. You can tell it to get rid of all the old logs by running sudo journalctl --vacuum-time=1m
. This deletes any logs older than 1 minute.
Set swappiness to 1
If your linux installation has swap configured (most do) then idle processes eventually have memory pages stored on disk instead of system memory. This is desirable because it means that long lived idle processes aren't using system memory. How quickly this happens is controlled by a value called swappiness
. You can check this by running cat /proc/sys/vm/swappiness
. This should show you a number 0-100. It's usually 60 by default.
This value can be set to a lower number by editing /etc/sysctl.conf
as root. Usually there is no line for this value so you can just add a line like this
vm.swappiness = 1
A value of 1 allows processes to still be moved to swap. A value of 0 means processes will only be used to swap when completely out of memory. You can apply this change immediately by running sudo sysctl -p
.
Disable the IO scheduler
Any block device on linux has an associated IO scheduler. This works well enough for conventional hard drives. For a microSD card, the performance is usually pretty poor anyways. The IO scheduler does not necessarily improve performance. You can disable it often with no real loss of usability. This also uses slightly less CPU.
To disable the IO scheduler, you need to select the none
scheduler for the root filesystem device. You can run findmnt
and get an output like this
$ findmnt TARGET SOURCE FSTYPE OPTIONS / /dev/mmcblk0p1 │ ext4 rw,noatime,nodiratime,errors=remount-ro,commit=600 ├─/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime │ ├─/sys/kernel/security securityfs securityfs rw,nosuid,nodev,noexec,relatime │ ├─/sys/fs/cgroup tmpfs tmpfs ro,nosuid,nodev,noexec,mode=755 │ │ ├─/sys/fs/cgroup/unified cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate │ │ ├─/sys/fs/cgroup/systemd cgroup cgroup rw,nosuid,nodev,noexec,relatime,xattr,name=systemd │ │ ├─/sys/fs/cgroup/rdma cgroup cgroup rw,nosuid,nodev,noexec,relatime,rdma │ │ ├─/sys/fs/cgroup/memory cgroup cgroup rw,nosuid,nodev,noexec,relatime,memory │ │ ├─/sys/fs/cgroup/net_cls,net_prio cgroup cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio │ │ ├─/sys/fs/cgroup/devices cgroup cgroup rw,nosuid,nodev,noexec,relatime,devices │ │ ├─/sys/fs/cgroup/cpuset cgroup cgroup rw,nosuid,nodev,noexec,relatime,cpuset │ │ ├─/sys/fs/cgroup/blkio cgroup cgroup rw,nosuid,nodev,noexec,relatime,blkio │ │ ├─/sys/fs/cgroup/cpu,cpuacct cgroup cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct │ │ ├─/sys/fs/cgroup/perf_event cgroup cgroup rw,nosuid,nodev,noexec,relatime,perf_event │ │ ├─/sys/fs/cgroup/pids cgroup cgroup rw,nosuid,nodev,noexec,relatime,pids │ │ ├─/sys/fs/cgroup/hugetlb cgroup cgroup rw,nosuid,nodev,noexec,relatime,hugetlb │ │ └─/sys/fs/cgroup/freezer cgroup cgroup rw,nosuid,nodev,noexec,relatime,freezer │ ├─/sys/fs/pstore pstore pstore rw,nosuid,nodev,noexec,relatime │ ├─/sys/fs/bpf none bpf rw,nosuid,nodev,noexec,relatime,mode=700 │ ├─/sys/kernel/debug debugfs debugfs rw,nosuid,nodev,noexec,relatime │ │ └─/sys/kernel/debug/tracing tracefs tracefs rw,nosuid,nodev,noexec,relatime │ ├─/sys/kernel/tracing tracefs tracefs rw,nosuid,nodev,noexec,relatime │ ├─/sys/fs/fuse/connections fusectl fusectl rw,nosuid,nodev,noexec,relatime │ └─/sys/kernel/config configfs configfs rw,nosuid,nodev,noexec,relatime ├─/proc proc proc rw,nosuid,nodev,noexec,relatime │ └─/proc/sys/fs/binfmt_misc systemd-1 autofs rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxpro ├─/dev udev devtmpfs rw,nosuid,noexec,relatime,size=425668k,nr_inodes=106 │ ├─/dev/pts devpts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=00 │ ├─/dev/shm tmpfs tmpfs rw,nosuid,nodev │ ├─/dev/hugepages hugetlbfs hugetlbfs rw,relatime,pagesize=2M │ └─/dev/mqueue mqueue mqueue rw,nosuid,nodev,noexec,relatime ├─/run tmpfs tmpfs rw,nosuid,nodev,noexec,relatime,size=100156k,mode=75 │ ├─/run/lock tmpfs tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k │ └─/run/user/1000 tmpfs tmpfs rw,nosuid,nodev,relatime,size=100152k,mode=700,uid=1 ├─/tmp tmpfs tmpfs rw,nosuid,relatime ├─/var/log.hdd /dev/mmcblk0p1[/var/log] │ ext4 rw,noatime,nodiratime,errors=remount-ro,commit=600 └─/var/log /dev/zram1 ext4 rw,relatime,discard
The only line we care about is the first one listed as /
. The source in my example is /dev/mmcblk0p1
. The name of the device is mmcblk0p1
. The current scheduler can be checked by running
$ cat /sys/block/mmcblk0/queue/scheduler none mq-deadline kyber [bfq]
The entry with the brackets around it is the current scheduler. If the brackets are around [none]
then the IO scheduler is already disabled. If it is not set, then a udev rule can be added to do so automatically.
Create the file /etc/udev/rules.d/99-scheduler.rules
. Only one line needs to be added
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="mmcblk0p1", ATTR{queue/scheduler}="none"
The value KERNEL=="mmcblk0p1"
identifies the device by its name, so you need to update it with your devices name. You can also use wildcards, such as KERNEL=="mmc*"
to match all devices with a name starting with mmc
.
To apply this change, run sudo udevadm control --reload-rules
followed by sudo udevadm trigger --type=devices --action=change
. Then check the current scheduler again
$ cat /sys/block/vda/queue/scheduler [none] mq-deadline kyber bfq