systemd-tmpfiles 如何工作?

systemd-tmpfiles 如何工作?

我试图/sys/bus/usb/devices/4-3/power/wakeup在每次启动时更改 的值(根据我的 4-3 lsusb,它是键盘 ID)。

默认值为:

# cat /sys/bus/usb/devices/4-3/power/wakeup
enabled

经典的“在线”编辑按预期工作:

# echo disabled > /sys/bus/usb/devices/4-3/power/wakeup
# cat /sys/bus/usb/devices/4-3/power/wakeup
disabled

我正在使用 systemd 发行版,所以我想使用编辑“临时文件”的 systemd 方式

我创建了以下文件:

# cat /etc/tmpfiles.d/disable-usb-wakeup.conf 
w /sys/bus/usb/devices/4-3/power/wakeup - - - - disabled

但每次启动后我仍然在此文件中保留默认值(即启用)

难道我做错了什么?

编辑:

这是另一个测试:

# cat /etc/tmpfiles.d/scheduler.conf 
w /sys/block/sda/queue/scheduler - - - - deadline

这个效果很好!启动后我得到:

# cat /sys/block/sda/queue/scheduler 
noop [deadline] cfq 

(默认的是 cfq 调度程序)

那么,为什么这个有效而另一个无效呢?

  • 因为/sys/bus/usb/devices/4-3/power/wakeup是一个符号链接到/sys/devices/pci0000:00/0000:00:12.1/usb4/4-3/?
  • 因为/sys/bus/usb/devices/4-3/power/wakeup只包含一个词? (即没有空格)

答案1

我不认为tmpfiles.d这是去这里的正确方法。你真的应该遵守udev规则。看:

udevadm info -a -p /sys/class/scsi_host/host*

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:11.0/ata1/host0/scsi_host/host0':
    KERNEL=="host0"
    SUBSYSTEM=="scsi_host"
    DRIVER==""
    ATTR{unchecked_isa_dma}=="0"
    ATTR{state}=="running"
    ATTR{cmd_per_lun}=="1"
...
    ATTR{ahci_host_version}=="10200"
    ATTR{prot_guard_type}=="0"
    ATTR{eh_deadline}=="off"
    ATTR{link_power_management_policy}=="max_performance"
    ATTR{host_busy}=="0"

  looking at parent device '/devices/pci0000:00/0000:00:11.0/ata1/host0':
    KERNELS=="host0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""
...

继续往上走,沿着父设备树向上走。但请考虑一下,仅使用上述信息,您就可以执行以下操作:

KERNEL=="host[0-5]", SUBSYSTEM=="scsi_host", ATTR{link_power_management_policy}="min_power"

我相信这对于你的大部分脚本来说都是如此。我想你应该把上面的内容放在规则 60 之后。实际上,您应该对其余部分执行此操作 - 只需sleep脚本中的部分就足够了 - 它意味着竞争条件。udev是添加和设置这些参数的参数 - 它是填充sysfs.只需要求它完成已经在做的工作即可。

对于您的键盘,您绝对应该做同样的事情 - 以及背光。只需从 获取有关这些设备的所需信息udevadm,编写一些规则udevadm test即可。

答案2

[我最初的想法是,这可能是因为 systemd-tmpfiles 使用流 I/O 并且不打算与 proc 或 sys 一起使用错误的。我的第二个假设,关于换行符的重要性,也是错误的......]

我刚刚看了一下/usr/lib/systemd/system/systemd-tmpfiles-setup.service,其中有一些可能感兴趣的内容:

[Unit]
Description=Recreate Volatile Files and Directories
Documentation=man:tmpfiles.d(5)
DefaultDependencies=no
Wants=local-fs.target
After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target
Before=sysinit.target shutdown.target

[...]

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/systemd-tmpfiles --create --remove

“想要”、“之后”和“之前”提供了有关何时发生这种情况的一些信息;我认为您的设备此时已注册,但可能存在某些问题随后的重置 sysfs 值。

最有用的位是 ExecStart 行,因为这是负责此服务的实际命令。这实际上在man systemd-tmpfiles

例如,在引导期间执行以下命令行以确保根据配置文件删除和创建所有临时和易失目录:

systemd-tmpfiles --删除 --创建

因此,要对此进行测试,请将 sysfs 值设置为“enabled”,然后尝试运行systemd-tmpfiles --create它将处理 /etc/tmpfiles.d 中的“w”指令。 如果这样有效的话(应该!),那么您就知道 systemd-tmpfile 方法很好,只是您必须在启动过程中稍后执行此操作,也许可以使用:

Requires=multi-user.target
After=multi-user.target

这意味着编写您自己的服务文件;如果由于某种原因它不起作用,您始终可以为脚本编写一个服务文件来使用echo.

答案3

我最近了解到 /etc/tmpfiles.d 在填充 /sys 之前被处理的困难方法,因此您必须创建正确的 udev 规则,以便每当设备出现时它们就会启用,或者......走肮脏的路(但如果您问我,一个更灵活的)并创建一个服务,该服务运行一个带有写入 /sys 的命令的脚本。

请查看此处有关如何创建此类脚本的示例,https://bbs.archlinux.org/viewtopic.php?id=148170您可以填写以下内容:

#### #!/bin/sh

sleep 2

#### # Enforce energy tweaks provided by PowerTop
echo min_power > /sys/class/scsi_host/host0/link_power_management_policy;
echo min_power > /sys/class/scsi_host/host1/link_power_management_policy;
echo min_power > /sys/class/scsi_host/host2/link_power_management_policy;
echo min_power > /sys/class/scsi_host/host3/link_power_management_policy;
echo min_power > /sys/class/scsi_host/host4/link_power_management_policy;
echo min_power > /sys/class/scsi_host/host5/link_power_management_policy;
echo 1 > /sys/module/snd_hda_intel/parameters/power_save;
echo auto > /sys/bus/pci/devices/0000:7f:00.1/power/control;
echo auto > /sys/bus/pci/devices/0000:01:00.1/power/control;

...

echo 4880 > /sys/class/backlight/intel_backlight/brightness

...

答案4

这可能有点矫枉过正,但就我而言,其他答案中提到的两种方法都失败了。这tmpfiles.d /sys/在填充条目之前进行更改并且该udev方法未找到该条目(这是一个虚拟网络设备br0)。因此,我创建了一个新的服务文件。只需创建一个新文件/etc/systemd/system/disable-usb-wakeup.service并将以下内容放入其中:

[Unit]
Description=Set multicast snoop to off
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c "echo disabled >> /sys/bus/usb/devices/4-3/power/wakeup"
RemainAfterExit=true
ExecStop=/usr/bin/bash -c "echo enabled >> /sys/bus/usb/devices/4-3/power/wakeup"
StandardOutput=journal

[Install]
WantedBy=multi-user.target

现在,为了确保该单元在每次启动时启动,只需发出以下命令:

# systemctl enable disable-usb-wakeup.service

你应该可以走了。

相关内容