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>
This commit is contained in:
parent
b5c4e4e9d1
commit
92d354cbe9
1 changed files with 21 additions and 17 deletions
|
@ -425,6 +425,24 @@ unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(comedi_bytes_per_scan);
|
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
|
* comedi_nscans_left() - Return the number of scans left in the command
|
||||||
* @s: COMEDI subdevice.
|
* @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 comedi_nscans_left(struct comedi_subdevice *s,
|
||||||
unsigned int nscans)
|
unsigned int nscans)
|
||||||
{
|
{
|
||||||
struct comedi_async *async = s->async;
|
|
||||||
struct comedi_cmd *cmd = &async->cmd;
|
|
||||||
|
|
||||||
if (nscans == 0) {
|
if (nscans == 0) {
|
||||||
unsigned int nbytes = comedi_buf_read_n_available(s);
|
unsigned int nbytes = comedi_buf_read_n_available(s);
|
||||||
|
|
||||||
nscans = nbytes / comedi_bytes_per_scan(s);
|
nscans = nbytes / comedi_bytes_per_scan(s);
|
||||||
}
|
}
|
||||||
|
return __comedi_nscans_left(s, nscans);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(comedi_nscans_left);
|
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;
|
struct comedi_cmd *cmd = &async->cmd;
|
||||||
|
|
||||||
if (cmd->stop_src == TRIG_COUNT) {
|
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;
|
||||||
unsigned int nscans = (nsamples / cmd->scan_end_arg) + 1;
|
unsigned int scans_left = __comedi_nscans_left(s, nscans);
|
||||||
unsigned int scans_left = comedi_nscans_left(s, nscans);
|
|
||||||
unsigned int scan_pos =
|
unsigned int scan_pos =
|
||||||
comedi_bytes_to_samples(s, async->scan_progress);
|
comedi_bytes_to_samples(s, async->scan_progress);
|
||||||
unsigned long long samples_left = 0;
|
unsigned long long samples_left = 0;
|
||||||
|
|
Loading…
Reference in a new issue