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

fbcon: fix locking harder

Okay so Alan's patch handled the case where there was no registered fbcon,
however the other path entered in set_con2fb_map pit.

In there we called fbcon_takeover, but we also took the console lock in a couple
of places. So push the console lock out to the callers of set_con2fb_map,

this means fbmem and switcheroo needed to take the lock around the fb notifier
entry points that lead to this.

This should fix the efifb regression seen by Maarten.

Tested-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Tested-by: Lu Hua <huax.lu@intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Dave Airlie and committed by
Dave Airlie
054430e7 e93a9a86

+13 -3
+3
drivers/gpu/vga/vga_switcheroo.c
··· 25 25 #include <linux/fb.h> 26 26 27 27 #include <linux/pci.h> 28 + #include <linux/console.h> 28 29 #include <linux/vga_switcheroo.h> 29 30 30 31 #include <linux/vgaarb.h> ··· 338 337 339 338 if (new_client->fb_info) { 340 339 struct fb_event event; 340 + console_lock(); 341 341 event.info = new_client->fb_info; 342 342 fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event); 343 + console_unlock(); 343 344 } 344 345 345 346 ret = vgasr_priv.handler->switchto(new_client->id);
+8 -3
drivers/video/console/fbcon.c
··· 842 842 * 843 843 * Maps a virtual console @unit to a frame buffer device 844 844 * @newidx. 845 + * 846 + * This should be called with the console lock held. 845 847 */ 846 848 static int set_con2fb_map(int unit, int newidx, int user) 847 849 { ··· 861 859 862 860 if (!search_for_mapped_con() || !con_is_bound(&fb_con)) { 863 861 info_idx = newidx; 864 - return fbcon_takeover(0); 862 + return do_fbcon_takeover(0); 865 863 } 866 864 867 865 if (oldidx != -1) ··· 869 867 870 868 found = search_fb_in_map(newidx); 871 869 872 - console_lock(); 873 870 con2fb_map[unit] = newidx; 874 871 if (!err && !found) 875 872 err = con2fb_acquire_newinfo(vc, info, unit, oldidx); ··· 895 894 if (!search_fb_in_map(info_idx)) 896 895 info_idx = newidx; 897 896 898 - console_unlock(); 899 897 return err; 900 898 } 901 899 ··· 3019 3019 } 3020 3020 #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ 3021 3021 3022 + /* called with console_lock held */ 3022 3023 static int fbcon_fb_unbind(int idx) 3023 3024 { 3024 3025 int i, new_idx = -1, ret = 0; ··· 3046 3045 return ret; 3047 3046 } 3048 3047 3048 + /* called with console_lock held */ 3049 3049 static int fbcon_fb_unregistered(struct fb_info *info) 3050 3050 { 3051 3051 int i, idx; ··· 3084 3082 return 0; 3085 3083 } 3086 3084 3085 + /* called with console_lock held */ 3087 3086 static void fbcon_remap_all(int idx) 3088 3087 { 3089 3088 int i; ··· 3129 3126 } 3130 3127 #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ 3131 3128 3129 + /* called with console_lock held */ 3132 3130 static int fbcon_fb_registered(struct fb_info *info) 3133 3131 { 3134 3132 int ret = 0, i, idx; ··· 3282 3278 ret = fbcon_fb_unregistered(info); 3283 3279 break; 3284 3280 case FB_EVENT_SET_CONSOLE_MAP: 3281 + /* called with console lock held */ 3285 3282 con2fb = event->data; 3286 3283 ret = set_con2fb_map(con2fb->console - 1, 3287 3284 con2fb->framebuffer, 1);
+2
drivers/video/fbmem.c
··· 1177 1177 event.data = &con2fb; 1178 1178 if (!lock_fb_info(info)) 1179 1179 return -ENODEV; 1180 + console_lock(); 1180 1181 event.info = info; 1181 1182 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); 1183 + console_unlock(); 1182 1184 unlock_fb_info(info); 1183 1185 break; 1184 1186 case FBIOBLANK: