| From e93a9a868792ad71cdd09d75e5a02d8067473c4e Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Fri, 25 Jan 2013 10:28:18 +1000 |
| Subject: fb: Yet another band-aid for fixing lockdep mess |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit e93a9a868792ad71cdd09d75e5a02d8067473c4e upstream. |
| |
| I've still got lockdep warnings even after Alan's patch, and it seems that |
| yet more band aids are required to paper over similar paths for |
| unbind_con_driver() and unregister_con_driver(). After this hack, lockdep |
| warnings are finally gone. |
| |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Cc: Alan Cox <alan@linux.intel.com> |
| Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> |
| Cc: Jiri Kosina <jkosina@suse.cz> |
| Tested-by: Sedat Dilek <sedat.dilek@gmail.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Dave Airlie <airlied@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/tty/vt/vt.c | 43 +++++++++++++++++++++++++++--------------- |
| drivers/video/console/fbcon.c | 4 +-- |
| drivers/video/fbmem.c | 4 +++ |
| include/linux/console.h | 1 |
| include/linux/vt_kern.h | 2 + |
| 5 files changed, 37 insertions(+), 17 deletions(-) |
| |
| --- a/drivers/tty/vt/vt.c |
| +++ b/drivers/tty/vt/vt.c |
| @@ -3165,6 +3165,18 @@ static int con_is_graphics(const struct |
| */ |
| int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) |
| { |
| + int retval; |
| + |
| + console_lock(); |
| + retval = do_unbind_con_driver(csw, first, last, deflt); |
| + console_unlock(); |
| + return retval; |
| +} |
| +EXPORT_SYMBOL(unbind_con_driver); |
| + |
| +/* unlocked version of unbind_con_driver() */ |
| +int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt) |
| +{ |
| struct module *owner = csw->owner; |
| const struct consw *defcsw = NULL; |
| struct con_driver *con_driver = NULL, *con_back = NULL; |
| @@ -3173,7 +3185,7 @@ int unbind_con_driver(const struct consw |
| if (!try_module_get(owner)) |
| return -ENODEV; |
| |
| - console_lock(); |
| + WARN_CONSOLE_UNLOCKED(); |
| |
| /* check if driver is registered and if it is unbindable */ |
| for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
| @@ -3186,10 +3198,8 @@ int unbind_con_driver(const struct consw |
| } |
| } |
| |
| - if (retval) { |
| - console_unlock(); |
| + if (retval) |
| goto err; |
| - } |
| |
| retval = -ENODEV; |
| |
| @@ -3205,15 +3215,11 @@ int unbind_con_driver(const struct consw |
| } |
| } |
| |
| - if (retval) { |
| - console_unlock(); |
| + if (retval) |
| goto err; |
| - } |
| |
| - if (!con_is_bound(csw)) { |
| - console_unlock(); |
| + if (!con_is_bound(csw)) |
| goto err; |
| - } |
| |
| first = max(first, con_driver->first); |
| last = min(last, con_driver->last); |
| @@ -3242,13 +3248,12 @@ int unbind_con_driver(const struct consw |
| |
| /* ignore return value, binding should not fail */ |
| do_bind_con_driver(defcsw, first, last, deflt); |
| - console_unlock(); |
| err: |
| module_put(owner); |
| return retval; |
| |
| } |
| -EXPORT_SYMBOL(unbind_con_driver); |
| +EXPORT_SYMBOL_GPL(do_unbind_con_driver); |
| |
| static int vt_bind(struct con_driver *con) |
| { |
| @@ -3635,9 +3640,18 @@ EXPORT_SYMBOL(register_con_driver); |
| */ |
| int unregister_con_driver(const struct consw *csw) |
| { |
| - int i, retval = -ENODEV; |
| + int retval; |
| |
| console_lock(); |
| + retval = do_unregister_con_driver(csw); |
| + console_unlock(); |
| + return retval; |
| +} |
| +EXPORT_SYMBOL(unregister_con_driver); |
| + |
| +int do_unregister_con_driver(const struct consw *csw) |
| +{ |
| + int i, retval = -ENODEV; |
| |
| /* cannot unregister a bound driver */ |
| if (con_is_bound(csw)) |
| @@ -3663,10 +3677,9 @@ int unregister_con_driver(const struct c |
| } |
| } |
| err: |
| - console_unlock(); |
| return retval; |
| } |
| -EXPORT_SYMBOL(unregister_con_driver); |
| +EXPORT_SYMBOL_GPL(do_unregister_con_driver); |
| |
| /* |
| * If we support more console drivers, this function is used |
| --- a/drivers/video/console/fbcon.c |
| +++ b/drivers/video/console/fbcon.c |
| @@ -3010,7 +3010,7 @@ static int fbcon_unbind(void) |
| { |
| int ret; |
| |
| - ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, |
| + ret = do_unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, |
| fbcon_is_default); |
| |
| if (!ret) |
| @@ -3083,7 +3083,7 @@ static int fbcon_fb_unregistered(struct |
| primary_device = -1; |
| |
| if (!num_registered_fb) |
| - unregister_con_driver(&fb_con); |
| + do_unregister_con_driver(&fb_con); |
| |
| return 0; |
| } |
| --- a/drivers/video/fbmem.c |
| +++ b/drivers/video/fbmem.c |
| @@ -1660,8 +1660,10 @@ static int do_unregister_framebuffer(str |
| |
| if (!lock_fb_info(fb_info)) |
| return -ENODEV; |
| + console_lock(); |
| event.info = fb_info; |
| ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); |
| + console_unlock(); |
| unlock_fb_info(fb_info); |
| |
| if (ret) |
| @@ -1676,7 +1678,9 @@ static int do_unregister_framebuffer(str |
| num_registered_fb--; |
| fb_cleanup_device(fb_info); |
| event.info = fb_info; |
| + console_lock(); |
| fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); |
| + console_unlock(); |
| |
| /* this may free fb info */ |
| put_fb_info(fb_info); |
| --- a/include/linux/console.h |
| +++ b/include/linux/console.h |
| @@ -77,6 +77,7 @@ extern const struct consw prom_con; /* S |
| int con_is_bound(const struct consw *csw); |
| int register_con_driver(const struct consw *csw, int first, int last); |
| int unregister_con_driver(const struct consw *csw); |
| +int do_unregister_con_driver(const struct consw *csw); |
| int take_over_console(const struct consw *sw, int first, int last, int deflt); |
| int do_take_over_console(const struct consw *sw, int first, int last, int deflt); |
| void give_up_console(const struct consw *sw); |
| --- a/include/linux/vt_kern.h |
| +++ b/include/linux/vt_kern.h |
| @@ -132,6 +132,8 @@ void vt_event_post(unsigned int event, u |
| int vt_waitactive(int n); |
| void change_console(struct vc_data *new_vc); |
| void reset_vc(struct vc_data *vc); |
| +extern int do_unbind_con_driver(const struct consw *csw, int first, int last, |
| + int deflt); |
| extern int unbind_con_driver(const struct consw *csw, int first, int last, |
| int deflt); |
| int vty_init(const struct file_operations *console_fops); |