lkml.org 
[lkml]   [2013]   [Feb]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 40/53] fb: rework locking to fix lock ordering on takeover
    Date
    3.0-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Alan Cox <alan@linux.intel.com>

    commit 50e244cc793d511b86adea24972f3a7264cae114 upstream.

    Adjust the console layer to allow a take over call where the caller
    already holds the locks. Make the fb layer lock in order.

    This is partly a band aid, the fb layer is terminally confused about the
    locking rules it uses for its notifiers it seems.

    [akpm@linux-foundation.org: remove stray non-ascii char, tidy comment]
    [akpm@linux-foundation.org: export do_take_over_console()]
    [airlied: cleanup another non-ascii char]
    Signed-off-by: Alan Cox <alan@linux.intel.com>
    Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
    Cc: Stephen Rothwell <sfr@canb.auug.org.au>
    Cc: Jiri Kosina <jkosina@suse.cz>
    Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
    Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
    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 | 93 +++++++++++++++++++++++++++++++-----------
    drivers/video/console/fbcon.c | 29 ++++++++++++-
    drivers/video/fbmem.c | 5 --
    drivers/video/fbsysfs.c | 3 +
    include/linux/console.h | 1
    5 files changed, 104 insertions(+), 27 deletions(-)

    --- a/drivers/tty/vt/vt.c
    +++ b/drivers/tty/vt/vt.c
    @@ -3016,7 +3016,7 @@ int __init vty_init(const struct file_op

    static struct class *vtconsole_class;

    -static int bind_con_driver(const struct consw *csw, int first, int last,
    +static int do_bind_con_driver(const struct consw *csw, int first, int last,
    int deflt)
    {
    struct module *owner = csw->owner;
    @@ -3027,7 +3027,7 @@ static int bind_con_driver(const struct
    if (!try_module_get(owner))
    return -ENODEV;

    - console_lock();
    + WARN_CONSOLE_UNLOCKED();

    /* check if driver is registered */
    for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    @@ -3112,11 +3112,22 @@ static int bind_con_driver(const struct

    retval = 0;
    err:
    - console_unlock();
    module_put(owner);
    return retval;
    };

    +
    +static int bind_con_driver(const struct consw *csw, int first, int last,
    + int deflt)
    +{
    + int ret;
    +
    + console_lock();
    + ret = do_bind_con_driver(csw, first, last, deflt);
    + console_unlock();
    + return ret;
    +}
    +
    #ifdef CONFIG_VT_HW_CONSOLE_BINDING
    static int con_is_graphics(const struct consw *csw, int first, int last)
    {
    @@ -3228,9 +3239,9 @@ int unbind_con_driver(const struct consw
    if (!con_is_bound(csw))
    con_driver->flag &= ~CON_DRIVER_FLAG_INIT;

    - console_unlock();
    /* ignore return value, binding should not fail */
    - bind_con_driver(defcsw, first, last, deflt);
    + do_bind_con_driver(defcsw, first, last, deflt);
    + console_unlock();
    err:
    module_put(owner);
    return retval;
    @@ -3508,28 +3519,18 @@ int con_debug_leave(void)
    }
    EXPORT_SYMBOL_GPL(con_debug_leave);

    -/**
    - * register_con_driver - register console driver to console layer
    - * @csw: console driver
    - * @first: the first console to take over, minimum value is 0
    - * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
    - *
    - * DESCRIPTION: This function registers a console driver which can later
    - * bind to a range of consoles specified by @first and @last. It will
    - * also initialize the console driver by calling con_startup().
    - */
    -int register_con_driver(const struct consw *csw, int first, int last)
    +static int do_register_con_driver(const struct consw *csw, int first, int last)
    {
    struct module *owner = csw->owner;
    struct con_driver *con_driver;
    const char *desc;
    int i, retval = 0;

    + WARN_CONSOLE_UNLOCKED();
    +
    if (!try_module_get(owner))
    return -ENODEV;

    - console_lock();
    -
    for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    con_driver = &registered_con_driver[i];

    @@ -3582,10 +3583,29 @@ int register_con_driver(const struct con
    }

    err:
    - console_unlock();
    module_put(owner);
    return retval;
    }
    +
    +/**
    + * register_con_driver - register console driver to console layer
    + * @csw: console driver
    + * @first: the first console to take over, minimum value is 0
    + * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
    + *
    + * DESCRIPTION: This function registers a console driver which can later
    + * bind to a range of consoles specified by @first and @last. It will
    + * also initialize the console driver by calling con_startup().
    + */
    +int register_con_driver(const struct consw *csw, int first, int last)
    +{
    + int retval;
    +
    + console_lock();
    + retval = do_register_con_driver(csw, first, last);
    + console_unlock();
    + return retval;
    +}
    EXPORT_SYMBOL(register_con_driver);

    /**
    @@ -3639,17 +3659,44 @@ EXPORT_SYMBOL(unregister_con_driver);
    * when a driver wants to take over some existing consoles
    * and become default driver for newly opened ones.
    *
    - * take_over_console is basically a register followed by unbind
    + * take_over_console is basically a register followed by unbind
    + */
    +int do_take_over_console(const struct consw *csw, int first, int last, int deflt)
    +{
    + int err;
    +
    + err = do_register_con_driver(csw, first, last);
    + /*
    + * If we get an busy error we still want to bind the console driver
    + * and return success, as we may have unbound the console driver
    + * but not unregistered it.
    + */
    + if (err == -EBUSY)
    + err = 0;
    + if (!err)
    + do_bind_con_driver(csw, first, last, deflt);
    +
    + return err;
    +}
    +EXPORT_SYMBOL_GPL(do_take_over_console);
    +
    +/*
    + * If we support more console drivers, this function is used
    + * when a driver wants to take over some existing consoles
    + * and become default driver for newly opened ones.
    + *
    + * take_over_console is basically a register followed by unbind
    */
    int take_over_console(const struct consw *csw, int first, int last, int deflt)
    {
    int err;

    err = register_con_driver(csw, first, last);
    - /* if we get an busy error we still want to bind the console driver
    + /*
    + * If we get an busy error we still want to bind the console driver
    * and return success, as we may have unbound the console driver
    -  * but not unregistered it.
    - */
    + * but not unregistered it.
    + */
    if (err == -EBUSY)
    err = 0;
    if (!err)
    --- a/drivers/video/console/fbcon.c
    +++ b/drivers/video/console/fbcon.c
    @@ -530,6 +530,33 @@ static int search_for_mapped_con(void)
    return retval;
    }

    +static int do_fbcon_takeover(int show_logo)
    +{
    + int err, i;
    +
    + if (!num_registered_fb)
    + return -ENODEV;
    +
    + if (!show_logo)
    + logo_shown = FBCON_LOGO_DONTSHOW;
    +
    + for (i = first_fb_vc; i <= last_fb_vc; i++)
    + con2fb_map[i] = info_idx;
    +
    + err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
    + fbcon_is_default);
    +
    + if (err) {
    + for (i = first_fb_vc; i <= last_fb_vc; i++)
    + con2fb_map[i] = -1;
    + info_idx = -1;
    + } else {
    + fbcon_has_console_bind = 1;
    + }
    +
    + return err;
    +}
    +
    static int fbcon_takeover(int show_logo)
    {
    int err, i;
    @@ -3122,7 +3149,7 @@ static int fbcon_fb_registered(struct fb
    }

    if (info_idx != -1)
    - ret = fbcon_takeover(1);
    + ret = do_fbcon_takeover(1);
    } else {
    for (i = first_fb_vc; i <= last_fb_vc; i++) {
    if (con2fb_map_boot[i] == idx)
    --- a/drivers/video/fbmem.c
    +++ b/drivers/video/fbmem.c
    @@ -1628,7 +1628,9 @@ static int do_register_framebuffer(struc
    event.info = fb_info;
    if (!lock_fb_info(fb_info))
    return -ENODEV;
    + console_lock();
    fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
    + console_unlock();
    unlock_fb_info(fb_info);
    return 0;
    }
    @@ -1831,11 +1833,8 @@ int fb_new_modelist(struct fb_info *info
    err = 1;

    if (!list_empty(&info->modelist)) {
    - if (!lock_fb_info(info))
    - return -ENODEV;
    event.info = info;
    err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
    - unlock_fb_info(info);
    }

    return err;
    --- a/drivers/video/fbsysfs.c
    +++ b/drivers/video/fbsysfs.c
    @@ -175,6 +175,8 @@ static ssize_t store_modes(struct device
    if (i * sizeof(struct fb_videomode) != count)
    return -EINVAL;

    + if (!lock_fb_info(fb_info))
    + return -ENODEV;
    console_lock();
    list_splice(&fb_info->modelist, &old_list);
    fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
    @@ -186,6 +188,7 @@ static ssize_t store_modes(struct device
    fb_destroy_modelist(&old_list);

    console_unlock();
    + unlock_fb_info(fb_info);

    return 0;
    }
    --- a/include/linux/console.h
    +++ b/include/linux/console.h
    @@ -78,6 +78,7 @@ 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 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);
    #ifdef CONFIG_HW_CONSOLE
    int con_debug_enter(struct vc_data *vc);

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2013-02-27 01:41    [W:3.910 / U:0.064 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site