diff options
author | Ian Abbott <abbotti@mev.co.uk> | 2013-04-04 13:59:18 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-04-05 21:33:29 (GMT) |
commit | db210da268ec537f8944ea5bc490184a6707c8a2 (patch) | |
tree | 5a5ed884253e3c9c582484a5b4c77c282ab2220e | |
parent | c6f5b4d587a46fc0713cecc30ef3993c59b7e41e (diff) | |
download | linux-fsl-qoriq-db210da268ec537f8944ea5bc490184a6707c8a2.tar.xz |
staging: comedi: add comedi_clear_board_dev()
Add local function `comedi_clear_board_dev()` as a safer alternative to
`comedi_clear_board_minor()` when we already have a pointer to a `struct
comedi_device`. It uses the board minor device number stored in the
`struct comedi_device` (which must have already been initialized) and
only clears the entry in `comedi_board_minor_table[]` if it points to
the specified `struct comedi_device`. Rather than returning the old
table entry, it returns `true` if the entry matched (and so has just
been cleared) and returns `false` otherwise.
Call `comedi_clear_board_dev()` instead of `comedi_clear_board_minor()`
in `comedi_unlocked_ioctl()` (in the code that frees a dynamically
allocated comedi device detached by the `COMEDI_DEVCONFIG` ioctl). That
ought to return `true` but check it just in case before freeing the
device. There is still a race condition here which needs to be dealt
with once we've implemented reference counting for `struct
comedi_device`s.
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/comedi/comedi_fops.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index b5e4bf1..dec04b9 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -120,6 +120,20 @@ static void comedi_device_cleanup(struct comedi_device *dev) mutex_destroy(&dev->mutex); } +static bool comedi_clear_board_dev(struct comedi_device *dev) +{ + unsigned int i = dev->minor; + bool cleared = false; + + mutex_lock(&comedi_board_minor_table_lock); + if (dev == comedi_board_minor_table[i]) { + comedi_board_minor_table[i] = NULL; + cleared = true; + } + mutex_unlock(&comedi_board_minor_table_lock); + return cleared; +} + static struct comedi_device *comedi_clear_board_minor(unsigned minor) { struct comedi_device *dev; @@ -1766,9 +1780,7 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, dev->minor >= comedi_num_legacy_minors) { /* Successfully unconfigured a dynamically * allocated device. Try and remove it. */ - struct comedi_device *devr; - devr = comedi_clear_board_minor(dev->minor); - if (dev == devr) { + if (comedi_clear_board_dev(dev)) { mutex_unlock(&dev->mutex); comedi_free_board_dev(dev); return rc; |