staging: comedi: change do_insn*_ioctl to allow more samples
Changes do_insn*_ioctl functions to allow for data lengths for each comedi_insn of up to 2^16. This patch also changes these functions to only allocate as much memory as is necessary for each comedi_insn, rather than allocating a fixed-sized scratch space. In testing some user-space code for the new INSN_DEVICE_CONFIG_GET_ROUTES facility with some newer hardware, I discovered that do_insn_ioctl and do_insnlist_ioctl limited the amount of data that can be passed into the kernel for insn's to a length of 256. For some newer hardware, the number of routes can be greater than 1000. Working around the old limits (256) would complicate the user-space/kernel interaction. The new upper limit is reasonable with current memory available and does not otherwise impact the memory footprint for any current or otherwise typical configuration. Signed-off-by: Spencer E. Olson <olsonse@umich.edu> Reviewed-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
354ea2ee6d
commit
f8bc1b2efa
@ -1501,25 +1501,21 @@ out:
|
||||
* data (for reads) to insns[].data pointers
|
||||
*/
|
||||
/* arbitrary limits */
|
||||
#define MAX_SAMPLES 256
|
||||
#define MIN_SAMPLES 16
|
||||
#define MAX_SAMPLES 65536
|
||||
static int do_insnlist_ioctl(struct comedi_device *dev,
|
||||
struct comedi_insnlist __user *arg, void *file)
|
||||
{
|
||||
struct comedi_insnlist insnlist;
|
||||
struct comedi_insn *insns = NULL;
|
||||
unsigned int *data = NULL;
|
||||
unsigned int max_n_data_required = MIN_SAMPLES;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (copy_from_user(&insnlist, arg, sizeof(insnlist)))
|
||||
return -EFAULT;
|
||||
|
||||
data = kmalloc_array(MAX_SAMPLES, sizeof(unsigned int), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
|
||||
if (!insns) {
|
||||
ret = -ENOMEM;
|
||||
@ -1533,13 +1529,26 @@ static int do_insnlist_ioctl(struct comedi_device *dev,
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < insnlist.n_insns; i++) {
|
||||
/* Determine maximum memory needed for all instructions. */
|
||||
for (i = 0; i < insnlist.n_insns; ++i) {
|
||||
if (insns[i].n > MAX_SAMPLES) {
|
||||
dev_dbg(dev->class_dev,
|
||||
"number of samples too large\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
max_n_data_required = max(max_n_data_required, insns[i].n);
|
||||
}
|
||||
|
||||
/* Allocate scratch space for all instruction data. */
|
||||
data = kmalloc_array(max_n_data_required, sizeof(unsigned int),
|
||||
GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < insnlist.n_insns; ++i) {
|
||||
if (insns[i].insn & INSN_MASK_WRITE) {
|
||||
if (copy_from_user(data, insns[i].data,
|
||||
insns[i].n * sizeof(unsigned int))) {
|
||||
@ -1593,22 +1602,27 @@ static int do_insn_ioctl(struct comedi_device *dev,
|
||||
{
|
||||
struct comedi_insn insn;
|
||||
unsigned int *data = NULL;
|
||||
unsigned int n_data = MIN_SAMPLES;
|
||||
int ret = 0;
|
||||
|
||||
data = kmalloc_array(MAX_SAMPLES, sizeof(unsigned int), GFP_KERNEL);
|
||||
if (copy_from_user(&insn, arg, sizeof(insn))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
n_data = max(n_data, insn.n);
|
||||
|
||||
/* This is where the behavior of insn and insnlist deviate. */
|
||||
if (insn.n > MAX_SAMPLES) {
|
||||
insn.n = MAX_SAMPLES;
|
||||
n_data = MAX_SAMPLES;
|
||||
}
|
||||
|
||||
data = kmalloc_array(n_data, sizeof(unsigned int), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (copy_from_user(&insn, arg, sizeof(insn))) {
|
||||
ret = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* This is where the behavior of insn and insnlist deviate. */
|
||||
if (insn.n > MAX_SAMPLES)
|
||||
insn.n = MAX_SAMPLES;
|
||||
if (insn.insn & INSN_MASK_WRITE) {
|
||||
if (copy_from_user(data,
|
||||
insn.data,
|
||||
|
Loading…
Reference in New Issue
Block a user