summaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/comedi_fops.c
diff options
context:
space:
mode:
authorIan Abbott2015-10-12 18:21:22 +0200
committerGreg Kroah-Hartman2015-10-13 19:29:48 +0200
commitfd060c8f4c93ee564510aa86724d27dca31b9e2a (patch)
treea3160ccc08e1f7f5603b8e6d96d5a45995f06fb3 /drivers/staging/comedi/comedi_fops.c
parentstaging: comedi: don't consider "unmunged" data when becoming non-busy (diff)
downloadkernel-qcow2-linux-fd060c8f4c93ee564510aa86724d27dca31b9e2a.tar.gz
kernel-qcow2-linux-fd060c8f4c93ee564510aa86724d27dca31b9e2a.tar.xz
kernel-qcow2-linux-fd060c8f4c93ee564510aa86724d27dca31b9e2a.zip
staging: comedi: do extra checks for becoming non-busy for "read"
`comedi_read()` is the handler for the "read" file operation for COMEDI devices. It mostly runs without using the main mutex of the COMEDI device, but uses the `attach_lock` rwsemaphore to protect against the COMEDI device becoming "detached". A file object can read data resulting from a COMEDI asynchonous command if it initiated the command. The COMEDI subdevice is marked as busy when the command is started. At some point, the "read" handler detects that the command has terminated and all available data has been read and so marks the subdevice as non-busy. In order to mark the subdevice as non-busy, the "read" handler needs to release the `attach_lock` rwsemaphore and `acquire the main `mutex`. There is a vulnerable point between the two, so it checks that the device is still attached after acquiring the mutex. However, it does not currently check that the conditions for becoming non-busy still hold. Add some more checks that the subdevice is still busy with a command initiated by the same file object, that command is in the correct direction (in case the subdevice supports both "read" and "write"), that command has terminated, and has no data available to be read. 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.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index c74c50a6e52d..49c46651ad23 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2567,14 +2567,17 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
* sufficient (unless there have been 2**32 detaches in the
* meantime!), but check the subdevice pointer as well just in
* case.
+ *
+ * Also check the subdevice is still in a suitable state to
+ * become non-busy in case it changed behind our back.
*/
new_s = comedi_file_read_subdevice(file);
if (dev->attached && old_detach_count == dev->detach_count &&
- s == new_s && new_s->async == async) {
- if (become_nonbusy ||
- comedi_buf_read_n_available(s) == 0)
- do_become_nonbusy(dev, s);
- }
+ s == new_s && new_s->async == async && s->busy == file &&
+ !(async->cmd.flags & CMDF_WRITE) &&
+ !comedi_is_subdevice_running(s) &&
+ comedi_buf_read_n_available(s) == 0)
+ do_become_nonbusy(dev, s);
mutex_unlock(&dev->mutex);
}
out: