X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind-session-device.c;h=6605935f3c768d395a5de1ccc285429abc560f52;hp=b45f9ebe0cc50ba2fa5bbf9cd641dadad8697d20;hb=3a83f5223acbeb1235310798c4d3660121c8880f;hpb=831dedef66dbf2650a9dc41263e624fe08f3bb7a diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c index b45f9ebe0..6605935f3 100644 --- a/src/login/logind-session-device.c +++ b/src/login/logind-session-device.c @@ -46,9 +46,13 @@ static void session_device_notify(SessionDevice *sd, enum SessionDeviceNotificat _cleanup_dbus_message_unref_ DBusMessage *m = NULL; _cleanup_free_ char *path = NULL; const char *t = NULL; + uint32_t major, minor; assert(sd); + major = major(sd->dev); + minor = minor(sd->dev); + if (!sd->session->controller) return; @@ -68,8 +72,8 @@ static void session_device_notify(SessionDevice *sd, enum SessionDeviceNotificat switch (type) { case SESSION_DEVICE_RESUME: if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, major(sd->dev), - DBUS_TYPE_UINT32, minor(sd->dev), + DBUS_TYPE_UINT32, &major, + DBUS_TYPE_UINT32, &minor, DBUS_TYPE_UNIX_FD, &sd->fd, DBUS_TYPE_INVALID)) return; @@ -88,8 +92,8 @@ static void session_device_notify(SessionDevice *sd, enum SessionDeviceNotificat } if (t && !dbus_message_append_args(m, - DBUS_TYPE_UINT32, major(sd->dev), - DBUS_TYPE_UINT32, minor(sd->dev), + DBUS_TYPE_UINT32, &major, + DBUS_TYPE_UINT32, &minor, DBUS_TYPE_STRING, &t, DBUS_TYPE_INVALID)) return; @@ -140,7 +144,7 @@ static int sd_drmdropmaster(int fd) { } static int session_device_open(SessionDevice *sd, bool active) { - int fd; + int fd, r; assert(sd->type != DEVICE_TYPE_UNKNOWN); @@ -151,9 +155,17 @@ static int session_device_open(SessionDevice *sd, bool active) { switch (sd->type) { case DEVICE_TYPE_DRM: - if (active) - sd_drmsetmaster(fd); - else { + if (active) { + /* Weird legacy DRM semantics might return an error + * even though we're master. No way to detect that so + * fail at all times and let caller retry in inactive + * state. */ + r = sd_drmsetmaster(fd); + if (r < 0) { + close(fd); + return r; + } + } else { /* DRM-Master is granted to the first user who opens a * device automatically (ughh, racy!). Hence, we just * drop DRM-Master in case we were the first. */ @@ -164,7 +176,6 @@ static int session_device_open(SessionDevice *sd, bool active) { if (!active) sd_eviocrevoke(fd); break; - case DEVICE_TYPE_FBDEV: case DEVICE_TYPE_UNKNOWN: default: /* fallback for devices wihout synchronizations */ @@ -201,14 +212,6 @@ static int session_device_start(SessionDevice *sd) { close_nointr_nofail(sd->fd); sd->fd = r; break; - case DEVICE_TYPE_FBDEV: - /* fbdev devices have no way to synchronize access. Moreover, - * they mostly operate through mmaps() without any pageflips - * and modesetting, so there is no way for us to prevent access - * but tear down mmaps. - * That would be quite expensive to do on a per-fd context. So - * ignore legcy fbdev and let its users feel the pain they asked - * for when deciding for fbdev. */ case DEVICE_TYPE_UNKNOWN: default: /* fallback for devices wihout synchronizations */ @@ -240,7 +243,6 @@ static void session_device_stop(SessionDevice *sd) { * protection this way. */ sd_eviocrevoke(sd->fd); break; - case DEVICE_TYPE_FBDEV: case DEVICE_TYPE_UNKNOWN: default: /* fallback for devices without synchronization */ @@ -258,10 +260,7 @@ static DeviceType detect_device_type(struct udev_device *dev) { subsystem = udev_device_get_subsystem(dev); type = DEVICE_TYPE_UNKNOWN; - if (streq_ptr(subsystem, "graphics")) { - if (!streq(sysname, "fbcon") && startswith(sysname, "fb")) - type = DEVICE_TYPE_FBDEV; - } else if (streq_ptr(subsystem, "drm")) { + if (streq_ptr(subsystem, "drm")) { if (startswith(sysname, "card")) type = DEVICE_TYPE_DRM; } else if (streq_ptr(subsystem, "input")) { @@ -302,8 +301,7 @@ static int session_device_verify(SessionDevice *sd) { goto err_dev; } sp = udev_device_get_syspath(dev); - } else if (sd->type != DEVICE_TYPE_FBDEV && - sd->type != DEVICE_TYPE_DRM) { + } else if (sd->type != DEVICE_TYPE_DRM) { /* Prevent opening unsupported devices. Especially devices of * subsystem "input" must be opened via the evdev node as * we require EVIOCREVOKE. */ @@ -380,9 +378,17 @@ int session_device_new(Session *s, dev_t dev, SessionDevice **out) { * revoke access and thus invalidate the fd. But this is still needed * to pass a valid fd back. */ sd->active = session_is_active(s); - sd->fd = session_device_open(sd, sd->active); - if (sd->fd < 0) - goto error; + r = session_device_open(sd, sd->active); + if (r < 0) { + /* EINVAL _may_ mean a master is active; retry inactive */ + if (sd->active && r == -EINVAL) { + sd->active = false; + r = session_device_open(sd, false); + } + if (r < 0) + goto error; + } + sd->fd = r; LIST_PREPEND(SessionDevice, sd_by_device, sd->device->session_devices, sd);