Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

udev rule executed too early? #61

Closed
RasmusWL opened this issue Nov 6, 2016 · 20 comments · Fixed by #62
Closed

udev rule executed too early? #61

RasmusWL opened this issue Nov 6, 2016 · 20 comments · Fixed by #62

Comments

@RasmusWL
Copy link
Contributor

RasmusWL commented Nov 6, 2016

After getting the udev rule to work, I am sometimes running into trouble, where disconnecting an external monitor changes the profile to external monitor, and connecting an external monitor changes the profile to only my laptop. So it's doing the opposite of what it should).

My guess is that autorandr is run too "early", such that the output of xrandr does not reflect the actual state of things.

If I have time one of the next days, I'll try to look into it.

@phillipberndt
Copy link
Owner

Seems like it is. Maybe it suffices to run xrandr -q twice in a row? However, if what you're after is delaying autorandr execution by some seconds:

udev kills external processes after some time, so we cannot sleep for long times. Using systemd might be an option: We can generate a device unit using an udev rule that "wants" the autorandr service unit to run. Of course, we'd have to change the unit file to RemainAfterExit=no then.

(I have never used that feature before, so I'd have to look into this as well.)

phillipberndt added a commit that referenced this issue Nov 15, 2016
@phillipberndt
Copy link
Owner

Here's a simple workaround: In the predetect branch, I've added support for a new script hook, predetect, which is run before autorandr calls xrandr to detect the current config. You can simply put a sleep 1 inside there, or another xrandr -q. As mentioned above, it might happen that udev kills autorandr while it sleeps.

Is this a viable solution for the problems you're experiencing?

phillipberndt added a commit that referenced this issue Nov 15, 2016
@phillipberndt
Copy link
Owner

Regarding my earlier suggestion: I just attempted to do it that way. That doesn't work: At least with my Intel card, I only receive CHANGE events in udev, not additions and removal of devices. At the first change after installing the udev rule, systemd creates a device unit, but for every later change, it just does nothing. 😞

But we could combine both ideas. See the systemd-change branch: I now invoke the systemd unit from the udev rule. This way, the timeout from udev does not apply and you can safely use a predetect script to wait a few seconds.

@ghost
Copy link

ghost commented May 30, 2017

@phillipberndt

But we could combine both ideas. See the systemd-change branch: I now invoke the systemd unit from the udev rule. This way, the timeout from udev does not apply and you can safely use a predetect script to wait a few seconds.

Hi. On NixOS distro, having an udev rule which invokes autorandr systemd unit breaks systemd-udev-settle service at computer boot. Do you have an idea why it may happen? Thanks.

@phillipberndt
Copy link
Owner

Breaks in which sense? Does it hang? Does it help to edit the udev rule to execute

/bin/sh -c "systemctl is-active -q systemd-udev-trigger.service && systemctl start autorandr.service"

instead of running autorandr directly? (systemd-udev-trigger.service activates systemd-udev-settle service, so this change should modify the rule such that it becomes inactive until systemd-udev-settle service is loaded.)

@ghost
Copy link

ghost commented May 31, 2017

@phillipberndt At the computer boot at some stage a message A start job is running for udev wait for Complete Device Initialization (..s / 3min) appears and the boot pauses for ~2min.

Thank you! Your rule helps, though only after changing systemd-udev-trigger.service to systemd-udev-settle.service

Failure log:

$ systemctl status autorandr
* autorandr.service - autorandr execution hook
   Loaded: loaded (/nix/store/77dn24rn9bsd78z4w4xwi66zm5hxw9qa-autorandr-unstable-2017-01-22/lib/systemd/system/autorandr.service; linked; vendor preset: enabled)
   Active: inactive (dead)

May 31 17:22:30 nixos systemd[1]: Starting autorandr execution hook...
May 31 17:22:31 nixos systemd[1]: Started autorandr execution hook.
May 31 17:22:31 nixos systemd[1]: Starting autorandr execution hook...
May 31 17:22:31 nixos systemd[1]: Started autorandr execution hook.
May 31 17:22:31 nixos systemd[1]: Starting autorandr execution hook...
May 31 17:22:31 nixos systemd[1]: Started autorandr execution hook.
May 31 17:22:31 nixos systemd[1]: Starting autorandr execution hook...
May 31 17:22:31 nixos systemd[1]: Started autorandr execution hook.
May 31 17:22:31 nixos systemd[1]: Starting autorandr execution hook...
May 31 17:22:31 nixos systemd[1]: Started autorandr execution hook.
$ systemctl status systemd-udev-settle
* systemd-udev-settle.service - udev Wait for Complete Device Initialization
   Loaded: loaded (/nix/store/px7a1kq4prjzw17c9pppssdmibqqdm2p-systemd-232/example/systemd/system/systemd-udev-settle.service; linked; vendor preset: enabled)
   Active: failed (Result: exit-code) since Wed 2017-05-31 17:22:30 MSK; 3min 24s ago
     Docs: man:udev(7)
           man:systemd-udevd.service(8)
  Process: 463 ExecStart=/nix/store/px7a1kq4prjzw17c9pppssdmibqqdm2p-systemd-232/bin/udevadm settle (code=exited, status=1/FAILURE)
 Main PID: 463 (code=exited, status=1/FAILURE)

May 31 17:22:30 nixos systemd[1]: systemd-udev-settle.service: Main process exited, code=exited, status=1/FAILURE
May 31 17:22:30 nixos systemd[1]: Failed to start udev Wait for Complete Device Initialization.
May 31 17:22:30 nixos systemd[1]: systemd-udev-settle.service: Unit entered failed state.
May 31 17:22:30 nixos systemd[1]: systemd-udev-settle.service: Failed with result 'exit-code'.

Success boot after switching to your rule (slighly modified as I wrote earlier):

$ systemctl status autorandr
* autorandr.service - autorandr execution hook
   Loaded: loaded (/nix/store/0ms7s92l654jdhwnlxbfg61a5chrvqw9-autorandr-unstable-2017-01-22/lib/systemd/system/autorandr.service; linked; vendor preset: enabled)
   Active: inactive (dead)
$ systemctl status systemd-udev-settle
* systemd-udev-settle.service - udev Wait for Complete Device Initialization
   Loaded: loaded (/nix/store/px7a1kq4prjzw17c9pppssdmibqqdm2p-systemd-232/example/systemd/system/systemd-udev-settle.service; linked; vendor preset: enabled)
   Active: active (exited) since Wed 2017-05-31 17:28:14 MSK; 35s ago
     Docs: man:udev(7)
           man:systemd-udevd.service(8)
  Process: 454 ExecStart=/nix/store/px7a1kq4prjzw17c9pppssdmibqqdm2p-systemd-232/bin/udevadm settle (code=exited, status=0/SUCCESS)
 Main PID: 454 (code=exited, status=0/SUCCESS)
    Tasks: 0 (limit: 4915)
   CGroup: /system.slice/systemd-udev-settle.service

Auto-switching outputs on monitor hotplug works.
Would you like to add the fix to your repo or should I add it to the distro package instead?

@phillipberndt
Copy link
Owner

Thank you! Your rule helps, though only after changing systemd-udev-trigger.service to systemd-
udev-settle.service

The problem with that is that systemd-udev-settle is apparently never activated unless it is needed (Does systemctl list-dependencies --reverse systemd-udev-settle.service show services on your system?), so unless your system actually uses systemd-udev-settle, adding this change to autorandr would break the udev rule for other users. (At least Mint is affected.)

If we can find a way to reliably detect whether this fix is required, I'll add the necessary changes to the Makefile, otherwise, I'd prefer if you'd fix this downstream :-)

@ghost
Copy link

ghost commented May 31, 2017

@phillipberndt
Thank you! You're absolutely right, it has only one service that depends on it

systemd-udev-settle.service
● └─display-manager.service

which exists only in this distro. I will make a downstream fix. Thank you much for your knowledge and help! :)

@ghost
Copy link

ghost commented Jun 3, 2017

@phillipberndt Hi again! NixOS people suggested the following universal udev rule ACTION=="change", SUBSYSTEM=="drm", TAG+="systemd", ENV{SYSTEMD_WANTS}="autorandr.service" What do you think? Ok for upstream?

@phillipberndt
Copy link
Owner

phillipberndt commented Jun 3, 2017 via email

@ghost
Copy link

ghost commented Jun 3, 2017

@phillipberndt Did a better testing and yes, you're right. Sorry then :-)

@ghost ghost mentioned this issue Jun 3, 2017
7 tasks
@phillipberndt
Copy link
Owner

FYI, the suggestions by @Mic92 sound good to me. If they work as expected please let me know, I'll include them upstream.

@phillipberndt phillipberndt reopened this Jun 4, 2017
@ghost
Copy link

ghost commented Jun 6, 2017

@phillipberndt

set BindsTo to the device node to systemd to make the service restart

I didn't get this. Don't we all use different devices?

As for second suggestion systemctl start --no-block autorandr.service, it works fine :-)

@phillipberndt
Copy link
Owner

I didn't get this. Don't we all use different devices?

You can refer to the instance name using "%i", e.g., have a look at "ifup@.service". (This would probably be a neater solution, I'm fine with the --no-block variant though. Let me know if you don't like to take the time to test the alternative..)

@ghost
Copy link

ghost commented Jun 6, 2017

@phillipberndt

¯_(ツ)_/¯ No success with that.

At first ACTION=="change", SUBSYSTEM=="drm", TAG+="systemd", ENV{SYSTEMD_WANTS}="autorandr@%E{DEVNAME}.service" didn't work because it generates SYSTEMD_WANTS=autorandr@/dev/dri/card0, but by some reason systemd doesn't strip prefix /, so BindsTo=%i.device generates -dev-dri-card0.device instead of dev-dri-card0.device. This was fixed by using ENV{SYSTEMD_WANTS}="autorandr@sys$devpath.service or ENV{SYSTEMD_WANTS}="autorandr@dev/$name.service, however the hotplug doesn't work. Statuses look ok.

$ udevadm monitor -p --subsystem=drm
UDEV  [138.264154] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
ACTION=change
DEVNAME=/dev/dri/card0
DEVPATH=/devices/pci0000:00/0000:00:02.0/drm/card0
DEVTYPE=drm_minor
HOTPLUG=1
ID_FOR_SEAT=drm-pci-0000_00_02_0
ID_PATH=pci-0000:00:02.0
ID_PATH_TAG=pci-0000_00_02_0
MAJOR=226
MINOR=0
PATH=/nix/store/xh8dj5l8k64y6w3snq3srgl4cr0c3jhb-udev-path/bin:/nix/store/xh8dj5l8k64y6w3snq3srgl4cr0c3jhb-udev-path/sbin
SEQNUM=2017
SUBSYSTEM=drm
SYSTEMD_WANTS=autorandr@sys/devices/pci0000:00/0000:00:02.0/drm/card0.service
TAGS=:seat:systemd:master-of-seat:uaccess:
USEC_INITIALIZED=9905706
$ systemctl status autorandr@sys/devices/pci0000:00/0000:00:02.0/drm/card0.service
* autorandr@sys-devices-pci0000:00-0000:00:02.0-drm-card0.service - test sys-devices-pci0000:00-0000:00:02.0-drm-card0
   Loaded: loaded (/nix/store/06wk3nwm8c8828f9sld8ff6mfka2rxq4-autorandr-unstable-2017-04-16/lib/systemd/system/autorandr@.service; enabled; vendor preset: enabled)
  Drop-In: /nix/store/16rlpf249h5y0p32h8n829lklbd4jknm-system-units/autorandr@.service.d
           `-overrides.conf
   Active: inactive (dead) since Tue 2017-06-06 17:28:01 MSK; 24min ago
  Process: 774 ExecStart=/nix/store/06wk3nwm8c8828f9sld8ff6mfka2rxq4-autorandr-unstable-2017-04-16/bin/autorandr --batch --change --default default (code=exited, status=0/SUCCESS)
 Main PID: 774 (code=exited, status=0/SUCCESS)

Jun 06 17:28:00 nixos systemd[1]: Starting test sys-devices-pci0000:00-0000:00:02.0-drm-card0...
Jun 06 17:28:01 nixos systemd[1]: Started test sys-devices-pci0000:00-0000:00:02.0-drm-card0.
$ systemctl status sys-devices-pci0000:00-0000:00:02.0-drm-card0.device
● sys-devices-pci0000:00-0000:00:02.0-drm-card0.device - /sys/devices/pci0000:00/0000:00:02.0/drm/card0
   Loaded: loaded
   Active: active (plugged) since Tue 2017-06-06 17:27:58 MSK; 26min ago
   Device: /sys/devices/pci0000:00/0000:00:02.0/drm/card0

@phillipberndt
Copy link
Owner

Let's stick with the --no-block then. (Let me know if you'd like me to add this; otherwise, I'll wait for a PR.)

@ghost
Copy link

ghost commented Jun 7, 2017

@phillipberndt Yes, please add :-) Since it's a tiny change I'll only slowdown the process. Thank you!

@phillipberndt
Copy link
Owner

Alright. Added & published as autorandr 1.1. Thanks for your help!

@ghost
Copy link

ghost commented Jun 7, 2017

@phillipberndt Great, thank you much! :)

@Mic92
Copy link

Mic92 commented Jun 8, 2017

It could be still possible to also encode device dependencies into the service by using:

$ systemd-escape /sys/devices/pci0000:00/0000:00:02.0/drm/card0
-sys-devices-pci0000:00-0000:00:02.0-drm-card0
$ systemctl start autorandr@$(systemd-escape /sys/devices/pci0000:00/0000:00:02.0/drm/card0)

But the current solution might be good enough for the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants