alistair23-linux/drivers/staging
Ian Abbott b34aa86f12 staging: comedi: fix circular locking dependency in comedi_mmap()
Mmapping a comedi data buffer with lockdep checking enabled produced the
following kernel debug messages:

======================================================
[ INFO: possible circular locking dependency detected ]
3.5.0-rc3-ija1+ #9 Tainted: G         C
-------------------------------------------------------
comedi_test/4160 is trying to acquire lock:
 (&dev->mutex#2){+.+.+.}, at: [<ffffffffa00313f4>] comedi_mmap+0x57/0x1d9 [comedi]

but task is already holding lock:
 (&mm->mmap_sem){++++++}, at: [<ffffffff810c96fe>] vm_mmap_pgoff+0x41/0x76

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #1 (&mm->mmap_sem){++++++}:
       [<ffffffff8106d0e8>] lock_acquire+0x97/0x105
       [<ffffffff810ce3bc>] might_fault+0x6d/0x90
       [<ffffffffa0031ffb>] do_devinfo_ioctl.isra.7+0x11e/0x14c [comedi]
       [<ffffffffa003227f>] comedi_unlocked_ioctl+0x256/0xe48 [comedi]
       [<ffffffff810f7fcd>] vfs_ioctl+0x18/0x34
       [<ffffffff810f87fd>] do_vfs_ioctl+0x382/0x43c
       [<ffffffff810f88f9>] sys_ioctl+0x42/0x65
       [<ffffffff81415c62>] system_call_fastpath+0x16/0x1b

-> #0 (&dev->mutex#2){+.+.+.}:
       [<ffffffff8106c528>] __lock_acquire+0x101d/0x1591
       [<ffffffff8106d0e8>] lock_acquire+0x97/0x105
       [<ffffffff8140c894>] mutex_lock_nested+0x46/0x2a4
       [<ffffffffa00313f4>] comedi_mmap+0x57/0x1d9 [comedi]
       [<ffffffff810d5816>] mmap_region+0x281/0x492
       [<ffffffff810d5c92>] do_mmap_pgoff+0x26b/0x2a7
       [<ffffffff810c971a>] vm_mmap_pgoff+0x5d/0x76
       [<ffffffff810d493f>] sys_mmap_pgoff+0xc7/0x10d
       [<ffffffff81004d36>] sys_mmap+0x16/0x20
       [<ffffffff81415c62>] system_call_fastpath+0x16/0x1b

other info that might help us debug this:

 Possible unsafe locking scenario:

       CPU0                    CPU1
       ----                    ----
  lock(&mm->mmap_sem);
                               lock(&dev->mutex#2);
                               lock(&mm->mmap_sem);
  lock(&dev->mutex#2);

 *** DEADLOCK ***

To avoid the circular dependency, just try to get the lock in
`comedi_mmap()` instead of blocking.  Since the comedi device's main mutex
is heavily used, do a down-read of its `attach_lock` rwsemaphore
instead.  Trying to down-read `attach_lock` should only fail if
some task has down-write locked it, and that is only done while the
comedi device is being attached to or detached from a low-level hardware
device.

Unfortunately, acquiring the `attach_lock` doesn't prevent another
task replacing the comedi data buffer we are trying to mmap.  The
details of the buffer are held in a `struct comedi_buf_map` and pointed
to by `s->async->buf_map` where `s` is the comedi subdevice whose buffer
we are trying to map.  The `struct comedi_buf_map` is already reference
counted with a `struct kref`, so we can stop it being freed prematurely.

Modify `comedi_mmap()` to call new function
`comedi_buf_map_from_subdev_get()` to read the subdevice's current
buffer map pointer and increment its reference instead of accessing
`async->buf_map` directly.  Call `comedi_buf_map_put()` to decrement the
reference once the buffer map structure has been dealt with.  (Note that
`comedi_buf_map_put()` does nothing if passed a NULL pointer.)

`comedi_buf_map_from_subdev_get()` checks the subdevice's buffer map
pointer has been set and the buffer map has been initialized enough for
`comedi_mmap()` to deal with it (specifically, check the `n_pages`
member has been set to a non-zero value).  If all is well, the buffer
map's reference is incremented and a pointer to it is returned.  The
comedi subdevice's spin-lock is used to protect the checks.  Also use
the spin-lock in `__comedi_buf_alloc()` and `__comedi_buf_free()` to
protect changes to the subdevice's buffer map structure pointer and the
buffer map structure's `n_pages` member.  (This checking of `n_pages` is
a bit clunky and I [Ian Abbott] plan to deal with it in the future.)

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Cc: <stable@vger.kernel.org> # 3.14.x, 3.15.x
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-04-16 11:41:45 -07:00
..
android Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2014-04-02 16:23:38 -07:00
bcm Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2014-04-02 16:23:38 -07:00
ced1401 Staging: ced1401: Fix no new typedef warning in ced_ioctl.h 2014-03-18 13:30:44 -07:00
comedi staging: comedi: fix circular locking dependency in comedi_mmap() 2014-04-16 11:41:45 -07:00
cptm1217
crystalhd staging: crystalhd: Fix no space before tabs 2014-03-16 21:32:32 -07:00
cxt1e1 Staging: cxt1e1: Fix externs should be avoided in .c files in comet.c 2014-03-19 09:17:23 -07:00
dgap staging: dgap: fix the rest of the checkpatch warnings in dgap.c 2014-03-19 13:54:39 -07:00
dgnc staging:dgnc: Removed assignments from if statements. 2014-03-17 16:42:47 -07:00
dgrp drivers/staging/dgrp:dgrp_tty.c: Fix line over 80 characters. 2014-03-18 10:53:21 -07:00
et131x Staging: et131x: Fix warning of prefer ether_addr_copy() in et131x.c 2014-03-08 20:27:48 -08:00
frontier Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2014-04-02 16:23:38 -07:00
ft1000 staging: ft1000: Fix line over 80 characters. 2014-03-19 13:41:28 -07:00
fwserial staging/fwserial: don't use PREPARE_WORK 2014-03-07 10:24:50 -05:00
gdm72xx staging: gdm72xx: remove completed TODO item 2014-03-16 19:53:58 -07:00
gdm724x Staging: gdm724x: Fix unchecked sscanf values in gdm_lte.c 2014-03-18 11:35:53 -07:00
goldfish staging: goldfish: Call free_irq in error path 2014-04-16 11:41:44 -07:00
gs_fpgaboot staging: gs_fpgaboot: remove __TIMESTAMP__ macro 2014-04-15 14:46:43 -07:00
iio staging: adc: mxs-lradc.c Fix line over 80 characters. 2014-03-19 13:41:27 -07:00
imx-drm Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux 2014-04-08 09:52:16 -07:00
keucr staging:keucr: Remove typedefs 2014-03-16 22:01:41 -07:00
line6 Staging driver pull request for 3.15-rc1 2014-04-01 16:45:00 -07:00
lustre Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-04-12 17:31:22 -07:00
media [media] msi3101: check I/O return values on stop streaming 2014-04-06 11:08:19 -03:00
mt29f_spinand
netlogic Staging:netlogic: Correct double assignment in xlr_net.c 2014-03-08 20:31:53 -08:00
nokia_h4p staging: nokia_h4p: Fix quoted string split across lines 2014-03-19 13:50:23 -07:00
nvec staging:nvec: Introduce the use of the managed version of kzalloc 2014-03-07 15:19:36 -08:00
octeon Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next 2014-04-02 20:53:45 -07:00
octeon-usb staging: octeon-usb: prevent memory corruption 2014-03-20 01:51:12 +00:00
olpc_dcon
ozwpan staging:ozwpan:Fix sparse warning of cast to restricted __le16 2014-03-18 11:58:45 -07:00
panel Staging: panel: Fix quoted string split across line in panel.c 2014-02-27 12:29:24 -08:00
phison
quickstart
rtl8188eu staging: rtl8188eu: remove spaces, correct counts to unbreak P2P ioctls 2014-04-15 13:52:14 -07:00
rtl8192e Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2014-04-02 16:23:38 -07:00
rtl8192u Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2014-04-02 16:23:38 -07:00
rtl8712 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2014-04-02 16:23:38 -07:00
rtl8723au staging: r8723au: Add missing initialization of change_inx in sort algorithm 2014-04-16 11:41:45 -07:00
rtl8821ae staging/rtl8821ae: Fix OOM handling in _rtl_init_deferred_work() 2014-04-15 11:39:09 -07:00
rts5139 staging: rts5139: Added in sd_cprm.c an include to fix a sparse warning 2014-03-16 17:41:13 -07:00
rts5208 staging: rts5208: Fix line over 80 characters. 2014-03-18 11:56:51 -07:00
sbe-2t3e3 /drivers/staging/sbe2t3e3: Fixed left brace to be on the previous line 2014-03-10 15:06:22 -07:00
sep staging: sep: Add fallthrough comment 2014-03-16 17:52:00 -07:00
serqt_usb2 drivers/staging/serqt_usb2:serqt_usb2.c Fix line over 80 characters. 2014-03-18 11:18:05 -07:00
silicom staging/silicom/bypasslib/bp_ioctl.h Fix do not add new typedefs. 2014-03-18 11:55:31 -07:00
slicoss staging: slicoss: free IO remapping on failure 2014-03-18 12:11:55 -07:00
speakup staging: speakup: fix misuse of kstrtol() in handle_goto() 2014-04-16 11:41:44 -07:00
ste_rmi4
tidspbridge staging/tidspbridge/rmgr/mgr.c Fix quoted string split across lines 2014-03-19 09:27:39 -07:00
unisys Staging: unisys: use after free in list_for_each() 2014-04-16 11:41:45 -07:00
usbip staging/usbip: fix store_attach() sscanf return value check 2014-04-15 14:43:01 -07:00
vme staging: vme: fix memory leak in vme_user_probe() 2014-04-15 14:46:43 -07:00
vt6655 staging:vt6655: Fix sparse warnings of using plain integer as NULL pointer 2014-03-18 11:01:21 -07:00
vt6656 staging: vt6656: s_uGetRTSCTSRsvTime fix return. 2014-03-19 09:00:19 -07:00
winbond staging: winbond: Fix line over 80 characters. 2014-03-19 09:27:39 -07:00
wlags49_h2 Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next 2014-04-02 20:53:45 -07:00
wlags49_h25
wlan-ng Staging: wlan-ng: Fix smatch warning potential null reference 2014-03-19 13:41:27 -07:00
xgifb Staging: xgifb: Fix quoted string split across lines in XGI_main_26.c 2014-02-28 14:29:38 -08:00
xillybus staging: xillybus: XILLYBUS_PCIE depends on PCI_MSI 2014-03-21 12:24:09 -07:00
Kconfig staging: delete rtl8187se wireless driver 2014-04-16 11:35:54 -07:00
Makefile staging: delete rtl8187se wireless driver 2014-04-16 11:35:54 -07:00
staging.c