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>
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#include <linux/fb.h>
|
#include <linux/fb.h>
|
||||||
|
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/console.h>
|
||||||
#include <linux/vga_switcheroo.h>
|
#include <linux/vga_switcheroo.h>
|
||||||
|
|
||||||
#include <linux/vgaarb.h>
|
#include <linux/vgaarb.h>
|
||||||
@@ -337,8 +338,10 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
|
|||||||
|
|
||||||
if (new_client->fb_info) {
|
if (new_client->fb_info) {
|
||||||
struct fb_event event;
|
struct fb_event event;
|
||||||
|
console_lock();
|
||||||
event.info = new_client->fb_info;
|
event.info = new_client->fb_info;
|
||||||
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
|
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
|
||||||
|
console_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = vgasr_priv.handler->switchto(new_client->id);
|
ret = vgasr_priv.handler->switchto(new_client->id);
|
||||||
|
@@ -842,6 +842,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
|
|||||||
*
|
*
|
||||||
* Maps a virtual console @unit to a frame buffer device
|
* Maps a virtual console @unit to a frame buffer device
|
||||||
* @newidx.
|
* @newidx.
|
||||||
|
*
|
||||||
|
* This should be called with the console lock held.
|
||||||
*/
|
*/
|
||||||
static int set_con2fb_map(int unit, int newidx, int user)
|
static int set_con2fb_map(int unit, int newidx, int user)
|
||||||
{
|
{
|
||||||
@@ -859,7 +861,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
|
|||||||
|
|
||||||
if (!search_for_mapped_con() || !con_is_bound(&fb_con)) {
|
if (!search_for_mapped_con() || !con_is_bound(&fb_con)) {
|
||||||
info_idx = newidx;
|
info_idx = newidx;
|
||||||
return fbcon_takeover(0);
|
return do_fbcon_takeover(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldidx != -1)
|
if (oldidx != -1)
|
||||||
@@ -867,7 +869,6 @@ static int set_con2fb_map(int unit, int newidx, int user)
|
|||||||
|
|
||||||
found = search_fb_in_map(newidx);
|
found = search_fb_in_map(newidx);
|
||||||
|
|
||||||
console_lock();
|
|
||||||
con2fb_map[unit] = newidx;
|
con2fb_map[unit] = newidx;
|
||||||
if (!err && !found)
|
if (!err && !found)
|
||||||
err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
|
err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
|
||||||
@@ -894,7 +895,6 @@ static int set_con2fb_map(int unit, int newidx, int user)
|
|||||||
if (!search_fb_in_map(info_idx))
|
if (!search_fb_in_map(info_idx))
|
||||||
info_idx = newidx;
|
info_idx = newidx;
|
||||||
|
|
||||||
console_unlock();
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3019,6 +3019,7 @@ static inline int fbcon_unbind(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
|
#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
|
||||||
|
|
||||||
|
/* called with console_lock held */
|
||||||
static int fbcon_fb_unbind(int idx)
|
static int fbcon_fb_unbind(int idx)
|
||||||
{
|
{
|
||||||
int i, new_idx = -1, ret = 0;
|
int i, new_idx = -1, ret = 0;
|
||||||
@@ -3045,6 +3046,7 @@ static int fbcon_fb_unbind(int idx)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called with console_lock held */
|
||||||
static int fbcon_fb_unregistered(struct fb_info *info)
|
static int fbcon_fb_unregistered(struct fb_info *info)
|
||||||
{
|
{
|
||||||
int i, idx;
|
int i, idx;
|
||||||
@@ -3082,6 +3084,7 @@ static int fbcon_fb_unregistered(struct fb_info *info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called with console_lock held */
|
||||||
static void fbcon_remap_all(int idx)
|
static void fbcon_remap_all(int idx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -3126,6 +3129,7 @@ static inline void fbcon_select_primary(struct fb_info *info)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
|
#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
|
||||||
|
|
||||||
|
/* called with console_lock held */
|
||||||
static int fbcon_fb_registered(struct fb_info *info)
|
static int fbcon_fb_registered(struct fb_info *info)
|
||||||
{
|
{
|
||||||
int ret = 0, i, idx;
|
int ret = 0, i, idx;
|
||||||
@@ -3278,6 +3282,7 @@ static int fbcon_event_notify(struct notifier_block *self,
|
|||||||
ret = fbcon_fb_unregistered(info);
|
ret = fbcon_fb_unregistered(info);
|
||||||
break;
|
break;
|
||||||
case FB_EVENT_SET_CONSOLE_MAP:
|
case FB_EVENT_SET_CONSOLE_MAP:
|
||||||
|
/* called with console lock held */
|
||||||
con2fb = event->data;
|
con2fb = event->data;
|
||||||
ret = set_con2fb_map(con2fb->console - 1,
|
ret = set_con2fb_map(con2fb->console - 1,
|
||||||
con2fb->framebuffer, 1);
|
con2fb->framebuffer, 1);
|
||||||
|
@@ -1177,8 +1177,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
|||||||
event.data = &con2fb;
|
event.data = &con2fb;
|
||||||
if (!lock_fb_info(info))
|
if (!lock_fb_info(info))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
console_lock();
|
||||||
event.info = info;
|
event.info = info;
|
||||||
ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
|
ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
|
||||||
|
console_unlock();
|
||||||
unlock_fb_info(info);
|
unlock_fb_info(info);
|
||||||
break;
|
break;
|
||||||
case FBIOBLANK:
|
case FBIOBLANK:
|
||||||
|
Reference in New Issue
Block a user