}
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
-/**
- * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
- * @fb_helper: driver-allocated fbdev helper, can be NULL
- *
- * This should be called from driver's drm &drm_driver.lastclose callback
- * when implementing an fbcon on top of kms using this helper. This ensures that
- * the user isn't greeted with a black screen when e.g. X dies.
- *
- * RETURNS:
- * Zero if everything went ok, negative error code otherwise.
- */
-int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
+static int
+__drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper,
+                                           bool force)
 {
        bool do_delayed;
        int ret;
                return 0;
 
        mutex_lock(&fb_helper->lock);
-       ret = drm_client_modeset_commit(&fb_helper->client);
+       if (force) {
+               /*
+                * Yes this is the _locked version which expects the master lock
+                * to be held. But for forced restores we're intentionally
+                * racing here, see drm_fb_helper_set_par().
+                */
+               ret = drm_client_modeset_commit_locked(&fb_helper->client);
+       } else {
+               ret = drm_client_modeset_commit(&fb_helper->client);
+       }
 
        do_delayed = fb_helper->delayed_hotplug;
        if (do_delayed)
 
        return ret;
 }
+
+/**
+ * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
+ * @fb_helper: driver-allocated fbdev helper, can be NULL
+ *
+ * This should be called from driver's drm &drm_driver.lastclose callback
+ * when implementing an fbcon on top of kms using this helper. This ensures that
+ * the user isn't greeted with a black screen when e.g. X dies.
+ *
+ * RETURNS:
+ * Zero if everything went ok, negative error code otherwise.
+ */
+int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
+{
+       return __drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper, false);
+}
 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
 
 #ifdef CONFIG_MAGIC_SYSRQ
 {
        struct drm_fb_helper *fb_helper = info->par;
        struct fb_var_screeninfo *var = &info->var;
+       bool force;
 
        if (oops_in_progress)
                return -EBUSY;
                return -EINVAL;
        }
 
-       drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
+       /*
+        * Normally we want to make sure that a kms master takes precedence over
+        * fbdev, to avoid fbdev flickering and occasionally stealing the
+        * display status. But Xorg first sets the vt back to text mode using
+        * the KDSET IOCTL with KD_TEXT, and only after that drops the master
+        * status when exiting.
+        *
+        * In the past this was caught by drm_fb_helper_lastclose(), but on
+        * modern systems where logind always keeps a drm fd open to orchestrate
+        * the vt switching, this doesn't work.
+        *
+        * To not break the userspace ABI we have this special case here, which
+        * is only used for the above case. Everything else uses the normal
+        * commit function, which ensures that we never steal the display from
+        * an active drm master.
+        */
+       force = var->activate & FB_ACTIVATE_KD_TEXT;
+
+       __drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper, force);
 
        return 0;
 }