aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi
diff options
context:
space:
mode:
authorIan Abbott <abbotti@mev.co.uk>2015-10-23 10:56:09 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-10-27 14:31:25 +0900
commit92d354cbe95fcaa0e5f795ad7706bc8393915c57 (patch)
treec157390ee302f6f530be5586b52e386c5a2e4a9d /drivers/staging/comedi
parentStaging: wilc1000: coreconfigurator: Remove unnecessary parentheses (diff)
downloadlinux-dev-92d354cbe95fcaa0e5f795ad7706bc8393915c57.tar.xz
linux-dev-92d354cbe95fcaa0e5f795ad7706bc8393915c57.zip
staging: comedi: fix extreme case of comedi_nsamples_left()
`comedi_nsamples_left(s, nsamples)` returns the number of samples remaining to complete an asynchronous command or the passed in `nsamples`, whichever is lower. However, it goes wrong in the extreme case of setting the `nsamples` parameter to `UINT_MAX` when the number of conversions per "scan" (`s->async->cmd.scan_end_arg`) is 1. It uses `comedi_nscans_remaining(s, nscans)` to determine the number of scans remaining, or the parameter `nscans`, whichever is lower. To determine the parameter `nscans`, it divides `nsamples` by the number of conversions per scan and adds 1. The addition of 1 is to avoid setting the parameter `nscans` to 0, as `comedi_nscans_remaining(s, nscans)` treats that value specially. However in the extreme case where `nsamples` is `UINT_MAX` and the number of samples per scan is 1, the addition of 1 to `nscans` overflows, producing the unwanted 0. Fix it by refactoring new a function `__comedi_nscans_remaining(s, nscans)` out of `comedi_nscans_remaining(s, nscans)`. The new function does everything except the special handling when `nscans` is 0. Change `comedi_nsamples_remaining()` to call the new function without adding 1 to `nscans` to avoid the overflow. This overflow bug doesn't affect any of the current COMEDI drivers. I stumbled across it while changing to one of the drivers. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r--drivers/staging/comedi/drivers.c38
1 files changed, 21 insertions, 17 deletions
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index aae94815b593..b63dd2ef78b5 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -425,6 +425,24 @@ unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
}
EXPORT_SYMBOL_GPL(comedi_bytes_per_scan);
+static unsigned int __comedi_nscans_left(struct comedi_subdevice *s,
+ unsigned int nscans)
+{
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+
+ if (cmd->stop_src == TRIG_COUNT) {
+ unsigned int scans_left = 0;
+
+ if (async->scans_done < cmd->stop_arg)
+ scans_left = cmd->stop_arg - async->scans_done;
+
+ if (nscans > scans_left)
+ nscans = scans_left;
+ }
+ return nscans;
+}
+
/**
* comedi_nscans_left() - Return the number of scans left in the command
* @s: COMEDI subdevice.
@@ -442,25 +460,12 @@ EXPORT_SYMBOL_GPL(comedi_bytes_per_scan);
unsigned int comedi_nscans_left(struct comedi_subdevice *s,
unsigned int nscans)
{
- struct comedi_async *async = s->async;
- struct comedi_cmd *cmd = &async->cmd;
-
if (nscans == 0) {
unsigned int nbytes = comedi_buf_read_n_available(s);
nscans = nbytes / comedi_bytes_per_scan(s);
}
-
- if (cmd->stop_src == TRIG_COUNT) {
- unsigned int scans_left = 0;
-
- if (async->scans_done < cmd->stop_arg)
- scans_left = cmd->stop_arg - async->scans_done;
-
- if (nscans > scans_left)
- nscans = scans_left;
- }
- return nscans;
+ return __comedi_nscans_left(s, nscans);
}
EXPORT_SYMBOL_GPL(comedi_nscans_left);
@@ -479,9 +484,8 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s,
struct comedi_cmd *cmd = &async->cmd;
if (cmd->stop_src == TRIG_COUNT) {
- /* +1 to force comedi_nscans_left() to return the scans left */
- unsigned int nscans = (nsamples / cmd->scan_end_arg) + 1;
- unsigned int scans_left = comedi_nscans_left(s, nscans);
+ unsigned int nscans = nsamples / cmd->scan_end_arg;
+ unsigned int scans_left = __comedi_nscans_left(s, nscans);
unsigned int scan_pos =
comedi_bytes_to_samples(s, async->scan_progress);
unsigned long long samples_left = 0;