forked from Minki/linux
staging: comedi: kcomedilib: protect against device detachment
The functions in "kcomedilib" need to prevent the comedi device being detached during their operation. This can be done by acquiring either the main mutex or the "attach lock" semaphore in the `struct comedi_device`. Use the attach lock when merely checking whether the device is attached. Use the mutex when processing a comedi instruction. Also, don't bother trying to manipulate the module use count of low-level comedi driver in `comedi_open()` and `comedi_close()`. If the device gets detached while it is "open", we wouldn't be able to decrement the module use count anyway. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
799a66ba36
commit
69e2387f3b
@ -50,10 +50,12 @@ struct comedi_device *comedi_open(const char *filename)
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
if (dev->attached && try_module_get(dev->driver->module))
|
||||
down_read(&dev->attach_lock);
|
||||
if (dev->attached)
|
||||
retval = dev;
|
||||
else
|
||||
retval = NULL;
|
||||
up_read(&dev->attach_lock);
|
||||
|
||||
if (retval == NULL)
|
||||
comedi_dev_put(dev);
|
||||
@ -62,13 +64,9 @@ struct comedi_device *comedi_open(const char *filename)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_open);
|
||||
|
||||
int comedi_close(struct comedi_device *d)
|
||||
int comedi_close(struct comedi_device *dev)
|
||||
{
|
||||
struct comedi_device *dev = (struct comedi_device *)d;
|
||||
|
||||
module_put(dev->driver->module);
|
||||
comedi_dev_put(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_close);
|
||||
@ -78,7 +76,14 @@ static int comedi_do_insn(struct comedi_device *dev,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct comedi_subdevice *s;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
if (!dev->attached) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* a subdevice instruction */
|
||||
if (insn->subdev >= dev->n_subdevices) {
|
||||
@ -125,6 +130,7 @@ static int comedi_do_insn(struct comedi_device *dev,
|
||||
s->busy = NULL;
|
||||
error:
|
||||
|
||||
mutex_unlock(&dev->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -174,9 +180,6 @@ int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
|
||||
unsigned int shift;
|
||||
int ret;
|
||||
|
||||
if (subdev >= dev->n_subdevices)
|
||||
return -EINVAL;
|
||||
|
||||
base_channel = CR_CHAN(base_channel);
|
||||
n_chan = comedi_get_n_channels(dev, subdev);
|
||||
if (base_channel >= n_chan)
|
||||
@ -216,23 +219,33 @@ int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
|
||||
unsigned int subd)
|
||||
{
|
||||
struct comedi_subdevice *s;
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (subd > dev->n_subdevices)
|
||||
return -ENODEV;
|
||||
|
||||
for (; subd < dev->n_subdevices; subd++) {
|
||||
s = &dev->subdevices[subd];
|
||||
if (s->type == type)
|
||||
return subd;
|
||||
}
|
||||
return -1;
|
||||
down_read(&dev->attach_lock);
|
||||
if (dev->attached)
|
||||
for (; subd < dev->n_subdevices; subd++) {
|
||||
s = &dev->subdevices[subd];
|
||||
if (s->type == type) {
|
||||
ret = subd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
up_read(&dev->attach_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type);
|
||||
|
||||
int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
|
||||
{
|
||||
struct comedi_subdevice *s = &dev->subdevices[subdevice];
|
||||
int n;
|
||||
|
||||
return s->n_chan;
|
||||
down_read(&dev->attach_lock);
|
||||
if (!dev->attached || subdevice >= dev->n_subdevices)
|
||||
n = 0;
|
||||
else
|
||||
n = dev->subdevices[subdevice].n_chan;
|
||||
up_read(&dev->attach_lock);
|
||||
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_get_n_channels);
|
||||
|
Loading…
Reference in New Issue
Block a user