Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/fbdev-generic: Clean up after failed probing

Clean up fbdev and client state if the probe function fails. It
used to leak allocated resources. Also reorder the individual steps
to simplify cleanup.

v2:
* move screen_size update into separate patches

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Acked-by: Zack Rusin <zackr@vmware.com>
Tested-by: Sui Jingfeng <suijingfeng@loongson.cn>
Link: https://patchwork.freedesktop.org/patch/msgid/20230320150751.20399-7-tzimmermann@suse.de

+29 -13
+29 -13
drivers/gpu/drm/drm_fbdev_generic.c
··· 77 77 struct drm_client_buffer *buffer; 78 78 struct fb_info *info; 79 79 size_t screen_size; 80 + void *screen_buffer; 80 81 u32 format; 81 82 int ret; 82 83 ··· 93 92 94 93 fb_helper->buffer = buffer; 95 94 fb_helper->fb = buffer->fb; 95 + 96 96 screen_size = buffer->gem->size; 97 + screen_buffer = vzalloc(screen_size); 98 + if (!screen_buffer) { 99 + ret = -ENOMEM; 100 + goto err_drm_client_framebuffer_delete; 101 + } 97 102 98 103 info = drm_fb_helper_alloc_info(fb_helper); 99 - if (IS_ERR(info)) 100 - return PTR_ERR(info); 101 - 102 - info->fbops = &drm_fbdev_fb_ops; 103 - info->screen_size = screen_size; 104 - info->fix.smem_len = screen_size; 105 - info->flags = FBINFO_DEFAULT; 104 + if (IS_ERR(info)) { 105 + ret = PTR_ERR(info); 106 + goto err_vfree; 107 + } 106 108 107 109 drm_fb_helper_fill_info(info, fb_helper, sizes); 108 110 109 - info->screen_buffer = vzalloc(screen_size); 110 - if (!info->screen_buffer) 111 - return -ENOMEM; 111 + info->fbops = &drm_fbdev_fb_ops; 112 + info->flags = FBINFO_DEFAULT; 113 + 114 + /* screen */ 112 115 info->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST; 113 - 116 + info->screen_buffer = screen_buffer; 114 117 info->fix.smem_start = page_to_phys(vmalloc_to_page(info->screen_buffer)); 118 + info->fix.smem_len = screen_size; 115 119 116 - /* Set a default deferred I/O handler */ 120 + /* deferred I/O */ 117 121 fb_helper->fbdefio.delay = HZ / 20; 118 122 fb_helper->fbdefio.deferred_io = drm_fb_helper_deferred_io; 119 123 120 124 info->fbdefio = &fb_helper->fbdefio; 121 125 ret = fb_deferred_io_init(info); 122 126 if (ret) 123 - return ret; 127 + goto err_drm_fb_helper_release_info; 124 128 125 129 return 0; 130 + 131 + err_drm_fb_helper_release_info: 132 + drm_fb_helper_release_info(fb_helper); 133 + err_vfree: 134 + vfree(screen_buffer); 135 + err_drm_client_framebuffer_delete: 136 + fb_helper->fb = NULL; 137 + fb_helper->buffer = NULL; 138 + drm_client_framebuffer_delete(buffer); 139 + return ret; 126 140 } 127 141 128 142 static void drm_fbdev_damage_blit_real(struct drm_fb_helper *fb_helper,