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>
This commit is contained in:
Ian Abbott 2013-04-04 14:59:18 +01:00 committed by Greg Kroah-Hartman
parent c6f5b4d587
commit db210da268
1 changed files with 15 additions and 3 deletions

View File

@ -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;