drm: Hold mode_config.lock to prevent hotplug whilst setting up crtcs
The fb_helper->connector_count is modified when a new connector is
constructed following a hotplug event (e.g. DP-MST). This causes trouble
for drm_setup_crtcs() and friends that assume that fb_helper is
constant:
[ 1250.872997] BUG: KASAN: slab-out-of-bounds in drm_setup_crtcs+0x320/0xf80 at addr
ffff88074cdd2608
[ 1250.873020] Write of size 40 by task kworker/u8:3/480
[ 1250.873039] CPU: 2 PID: 480 Comm: kworker/u8:3 Tainted: G U 4.9.0-rc6+ #285
[ 1250.873043] Hardware name: /NUC6i3SYB, BIOS SYSKLi35.86A.0024.2015.1027.2142 10/27/2015
[ 1250.873050] Workqueue: events_unbound async_run_entry_fn
[ 1250.873056]
ffff88070f9d78f0 ffffffff814b72aa ffff88074e40c5c0 ffff88074cdd2608
[ 1250.873067]
ffff88070f9d7918 ffffffff8124ff3c ffff88070f9d79b0 ffff88074cdd2600
[ 1250.873079]
ffff88074e40c5c0 ffff88070f9d79a0 ffffffff812501e4 0000000000000005
[ 1250.873090] Call Trace:
[ 1250.873099] [<
ffffffff814b72aa>] dump_stack+0x67/0x9d
[ 1250.873106] [<
ffffffff8124ff3c>] kasan_object_err+0x1c/0x70
[ 1250.873113] [<
ffffffff812501e4>] kasan_report_error+0x204/0x4f0
[ 1250.873120] [<
ffffffff81698df0>] ? drm_dev_printk+0x140/0x140
[ 1250.873127] [<
ffffffff81250ac3>] kasan_report+0x53/0x60
[ 1250.873134] [<
ffffffff81688b40>] ? drm_setup_crtcs+0x320/0xf80
[ 1250.873142] [<
ffffffff8124f18e>] check_memory_region+0x13e/0x1a0
[ 1250.873147] [<
ffffffff8124f5f3>] memset+0x23/0x40
[ 1250.873154] [<
ffffffff81688b40>] drm_setup_crtcs+0x320/0xf80
[ 1250.873161] [<
ffffffff810be7c5>] ? wake_up_q+0x45/0x80
[ 1250.873169] [<
ffffffff81b0c180>] ? mutex_lock_nested+0x5a0/0x5a0
[ 1250.873176] [<
ffffffff8168a0e6>] drm_fb_helper_initial_config+0x206/0x7a0
[ 1250.873183] [<
ffffffff81689ee0>] ? drm_fb_helper_set_par+0x90/0x90
[ 1250.873303] [<
ffffffffa0b68690>] ? intel_fbdev_fini+0x140/0x140 [i915]
[ 1250.873387] [<
ffffffffa0b686b2>] intel_fbdev_initial_config+0x22/0x40 [i915]
[ 1250.873391] [<
ffffffff810b50ff>] async_run_entry_fn+0x7f/0x270
[ 1250.873394] [<
ffffffff810a64b0>] process_one_work+0x3d0/0x960
[ 1250.873398] [<
ffffffff810a641d>] ? process_one_work+0x33d/0x960
[ 1250.873401] [<
ffffffff810a60e0>] ? max_active_store+0xf0/0xf0
[ 1250.873406] [<
ffffffff810f6f9d>] ? do_raw_spin_lock+0x10d/0x1a0
[ 1250.873413] [<
ffffffff810a767d>] worker_thread+0x8d/0x840
[ 1250.873419] [<
ffffffff810a75f0>] ? create_worker+0x2e0/0x2e0
[ 1250.873426] [<
ffffffff810b0454>] kthread+0x194/0x1c0
[ 1250.873432] [<
ffffffff810b02c0>] ? kthread_park+0x60/0x60
[ 1250.873438] [<
ffffffff810f095d>] ? trace_hardirqs_on+0xd/0x10
[ 1250.873446] [<
ffffffff810b02c0>] ? kthread_park+0x60/0x60
[ 1250.873453] [<
ffffffff810b02c0>] ? kthread_park+0x60/0x60
[ 1250.873457] [<
ffffffff81b12277>] ret_from_fork+0x27/0x40
[ 1250.873460] Object at
ffff88074cdd2608, in cache kmalloc-32 size: 32
However, when holding the mode_config.lock around the fb_helper, we have
to be careful of any callbacks that may reenter the fb_helper and so try
to reacquire the mode_config.lock (e.g. register_framebuffer). To avoid
the mutex recursion, we have to rearrange the sequence to move the
registration into the caller outside of the mode_config.lock.
v2: drop the 1; following the lockdep assertion inside the for(;;), I
anticipated an error that doesn't happen!
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98826
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel@ffwll.ch>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20161129120217.7344-1-chris@chris-wilson.co.uk