Skip to content

Commit

Permalink
staging: comedi: remove manually unconfigured dynamic devices
Browse files Browse the repository at this point in the history
If a dynamically allocated (non-legacy, and automatically configured)
comedi device has been successfully unconfigured by use of the
`COMEDI_DEVCONFIG` ioctl, then remove the device afterwards.
(Dynamically identified comedi devices are identified by their minor
device number being `comedi_num_legacy_minors` or greater.)  This is
done in `comedi_unlocked_ioctl()` on return from `do_devconfig_ioctl()`.

Note that there is an unlikely race condition with some other thread
that has just called `comedi_file_info_from_minor()` or
`comedi_dev_from_minor()` and is about to use the device, but that race
condition also exists for automatically removed devices and will be
dealt with properly once reference counting of comedi devices has been
implemented.  We do avoid a race condition between automatic removal and
removal by the `COMEDI_DEVCONFIG` ioctl though.

Also add an extra precaution in `do_devconfig_ioctl()` to avoid
configuring a dynamically allocated device since there is a tight
window avoiding the race condition where this could happen and the
device is about to be removed anyway.

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>
  • Loading branch information
Ian Abbott authored and Greg Kroah-Hartman committed Apr 5, 2013
1 parent 1f423cf commit 8ab4ed6
Showing 1 changed file with 20 additions and 0 deletions.
20 changes: 20 additions & 0 deletions drivers/staging/comedi/comedi_fops.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ struct comedi_file_info {
static DEFINE_SPINLOCK(comedi_file_info_table_lock);
static struct comedi_file_info *comedi_file_info_table[COMEDI_NUM_MINORS];

static struct comedi_file_info *comedi_clear_minor(unsigned minor);
static void comedi_free_board_file_info(struct comedi_file_info *info);

static struct comedi_file_info *comedi_file_info_from_minor(unsigned minor)
{
struct comedi_file_info *info;
Expand Down Expand Up @@ -490,6 +493,10 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
return -EINVAL;
}

if (dev->minor >= comedi_num_legacy_minors)
/* don't re-use dynamically allocated comedi devices */
return -EBUSY;

ret = comedi_device_attach(dev, &it);
if (ret == 0) {
if (!try_module_get(dev->driver->module)) {
Expand Down Expand Up @@ -1635,6 +1642,19 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
}
rc = do_devconfig_ioctl(dev,
(struct comedi_devconfig __user *)arg);
if (rc == 0) {
if (arg == 0 &&
dev->minor >= comedi_num_legacy_minors) {
/* Successfully unconfigured a dynamically
* allocated device. Try and remove it. */
info = comedi_clear_minor(dev->minor);
if (info) {
mutex_unlock(&dev->mutex);
comedi_free_board_file_info(info);
return rc;
}
}
}
goto done;
}

Expand Down

0 comments on commit 8ab4ed6

Please sign in to comment.