3

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
    
DCaugs
  • 133
  • What are the permissions on the rc.local file? – David King Dec 04 '15 at 20:54
  • So, it turns out, that was my issue. I eventually realized that the permissions needed to be adjusted, like so:

    chmod +x /etc/rc.d/rc.local

    However, I'm not posting that as an answer...I don't think this approach is really a best practice. @JdeBP's answer below definitely looks like a more sane solution.

    – DCaugs Dec 08 '15 at 13:38

2 Answers2

6

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/custom-readahead@.service:

[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}="custom-readahead@%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

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
JdeBP
  • 68,745
2

In CentOS 7, rc.local is not executable by default.

Run: chmod +x /etc/rc.d/rc.local

To enable it.