aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/comedi/comedi_fops.c
diff options
context:
space:
mode:
authorIan Abbott <abbotti@mev.co.uk>2013-04-04 14:58:54 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-05 14:33:18 -0700
commit8ab4ed6ef1c218cac4270cd20a714b83da6907a3 (patch)
tree874ecaa3480f2af30061ebb82355341fe271296d /drivers/staging/comedi/comedi_fops.c
parent1f423cfcf56052b462c4bceefb950921c9a0f495 (diff)
staging: comedi: remove manually unconfigured dynamic devices
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>
Diffstat (limited to 'drivers/staging/comedi/comedi_fops.c')
-rw-r--r--drivers/staging/comedi/comedi_fops.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index a155bf2c659..d80060a1497 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -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;
@@ -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)) {
@@ -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;
}