[PATCH] fb: fix lost console when the user unplugs a USB adapter

Bartlomiej Zolnierkiewicz b.zolnierkie at samsung.com
Tue Jul 3 14:52:19 UTC 2018


Hi,

On Sunday, June 03, 2018 11:46:29 AM Mikulas Patocka wrote:
> I have a USB display adapter using the udlfb driver and I use it on an ARM
> board that doesn't have any graphics card. When I plug the adapter in, the
> console is properly displayed, however when I unplug and re-plug the
> adapter, the console is not displayed and I can't access it until I reboot
> the board.
> 
> The reason is this:
> When the adapter is unplugged, dlfb_usb_disconnect calls
> unlink_framebuffer, then it waits until the reference count drops to zero
> and then it deallocates the framebuffer. However, the console that is
> attached to the framebuffer device keeps the reference count non-zero, so
> the framebuffer device is never destroyed. When the USB adapter is plugged
> again, it creates a new device /dev/fb1 and the console is not attached to
> it.
> 
> This patch fixes the bug by unbinding the console from unlink_framebuffer.
> The code to unbind the console is moved from do_unregister_framebuffer to
> a function unbind_console. When the console is unbound, the reference
> count drops to zero and the udlfb driver frees the framebuffer. When the
> adapter is plugged back, a new framebuffer is created and the console is
> attached to it.
> 
> Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
> Cc: stable at vger.kernel.org

After this change unbind_console() will be called twice in the standard
framebuffer unregister path:

- first time, directly by do_unregister_framebuffer()

- second time, indirectly by do_unregister_framebuffer()->unlink_framebuffer()

This doesn't look correctly.

Also why can't udlfb just use unregister_framebuffer() like all other
drivers (it uses unlink_framebuffer() and it is the only user of this
helper)?

> ---
>  drivers/video/fbdev/core/fbmem.c |   21 +++++++++++++++++----
>  1 file changed, 17 insertions(+), 4 deletions(-)
> 
> Index: linux-4.16.12/drivers/video/fbdev/core/fbmem.c
> ===================================================================
> --- linux-4.16.12.orig/drivers/video/fbdev/core/fbmem.c	2018-05-26 06:13:20.000000000 +0200
> +++ linux-4.16.12/drivers/video/fbdev/core/fbmem.c	2018-05-26 06:13:20.000000000 +0200
> @@ -1805,12 +1805,12 @@ static int do_register_framebuffer(struc
>  	return 0;
>  }
>  
> -static int do_unregister_framebuffer(struct fb_info *fb_info)
> +static int unbind_console(struct fb_info *fb_info)
>  {
>  	struct fb_event event;
> -	int i, ret = 0;
> +	int ret;
> +	int i = fb_info->node;
>  
> -	i = fb_info->node;
>  	if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
>  		return -EINVAL;
>  
> @@ -1825,6 +1825,16 @@ static int do_unregister_framebuffer(str
>  	unlock_fb_info(fb_info);
>  	console_unlock();
>  
> +	return ret;
> +}
> +
> +static int do_unregister_framebuffer(struct fb_info *fb_info)
> +{
> +	struct fb_event event;
> +	int ret;
> +
> +	ret = unbind_console(fb_info);
> +
>  	if (ret)
>  		return -EINVAL;
>  
> @@ -1835,7 +1845,7 @@ static int do_unregister_framebuffer(str
>  	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
>  		kfree(fb_info->pixmap.addr);
>  	fb_destroy_modelist(&fb_info->modelist);
> -	registered_fb[i] = NULL;
> +	registered_fb[fb_info->node] = NULL;
>  	num_registered_fb--;
>  	fb_cleanup_device(fb_info);
>  	event.info = fb_info;
> @@ -1860,6 +1870,9 @@ int unlink_framebuffer(struct fb_info *f
>  		device_destroy(fb_class, MKDEV(FB_MAJOR, i));
>  		fb_info->dev = NULL;
>  	}
> +
> +	unbind_console(fb_info);
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL(unlink_framebuffer);

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics



More information about the dri-devel mailing list