I am (probably obviously) a relatively new Linux user, so I’m already bracing for the barrage of “why aren’t you doing it this way instead…” comments. I’d love to hear them…but I would also really like to fundamentally understand why this isn’t working as is.
The details:
- I’m running CentOS 7+
- I’m attempting to modify the read-ahead values on my blockdev configs (for a database server)
- I’m able to implement the changes from cmd line, but I cannot persist them after reboot.
- Yes, I have rebooted. A lot.
- In an attempt to persist the changes I’ve modified the rc.local file.
-
The rc.local file is being implemented like this:
#!/bin/bash touch /var/lock/subsys/local /sbin/blockdev --setra 128 /dev/sda /sbin/blockdev --setra 128 /dev/dm-1 /sbin/blockdev --setra 128 /dev/dm-0
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Forget about rc.local.
You’re using CentOS 7. You have systemd. /etc/rc.local is a double backwards compatibility mechanism in systemd, because it is a backwards compatibility mechanism for a mechanism that was itself a compatibility mechanism in System 5 rc. And as shown by the mess in the AskUbuntu question hyperlinked below, using /etc/rc.local can go horribly wrong. So make a proper systemd service unit.
First, create a template service unit. For the sake of example, let’s call it /etc/systemd/system/[email protected]:
[Unit] Documentation=https://unix.stackexchange.com/questions/247436/ Description=Set custom read-ahead on storage device %I BindsTo=dev-%i.device [Service] Type=oneshot ExecStart=/sbin/blockdev --setra 128 /dev/%I
Arrange for that service unit to be started by the plug-and-play device manager (udev) when the appropriate devices arrive. Your rule, which you’ll have to tailor to your specific needs, will look something like:
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ENV{SYSTEMD_WANTS}="[email protected]%k"
The SYSTEMD_WANTS setting causes udev to start the named service — an instantiation of the template against the device %k. This service then runs blockdev.
There is apparently another way of doing this, which relies on udev’s ability to set these settings directly. For this, you don’t need the systemd template unit or instantiated services. Instead, simply instruct udev directly in its rule:
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{bdi/read_ahead_kb}="128"
Notice the difference between == and =.
There is no rc.local involved anywhere, either way.
Further reading
- https://unix.stackexchange.com/a/200281/5132
- https://unix.stackexchange.com/a/211927/5132
- Milosz Galazka (2015-05-11). How to enforce read-only mode on every connected USB storage device. sleeplessbeastie.
- https://unix.stackexchange.com/a/71409/5132
Method 2
In CentOS 7, rc.local is not executable by default.
Run: chmod +x /etc/rc.d/rc.local
To enable it.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0