|
@@ -1413,22 +1413,19 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
|
|
DPRINTK("subdevice busy\n");
|
|
|
return -EBUSY;
|
|
|
}
|
|
|
- s->busy = file;
|
|
|
|
|
|
/* make sure channel/gain list isn't too long */
|
|
|
if (cmd.chanlist_len > s->len_chanlist) {
|
|
|
DPRINTK("channel/gain list too long %u > %d\n",
|
|
|
cmd.chanlist_len, s->len_chanlist);
|
|
|
- ret = -EINVAL;
|
|
|
- goto cleanup;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
/* make sure channel/gain list isn't too short */
|
|
|
if (cmd.chanlist_len < 1) {
|
|
|
DPRINTK("channel/gain list too short %u < 1\n",
|
|
|
cmd.chanlist_len);
|
|
|
- ret = -EINVAL;
|
|
|
- goto cleanup;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
async->cmd = cmd;
|
|
@@ -1438,8 +1435,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
|
|
kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
|
|
|
if (!async->cmd.chanlist) {
|
|
|
DPRINTK("allocation failed\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto cleanup;
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
if (copy_from_user(async->cmd.chanlist, user_chanlist,
|
|
@@ -1491,6 +1487,9 @@ static int do_cmd_ioctl(struct comedi_device *dev,
|
|
|
|
|
|
comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
|
|
|
|
|
|
+ /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
|
|
|
+ * comedi_read() or comedi_write() */
|
|
|
+ s->busy = file;
|
|
|
ret = s->do_cmd(dev, s);
|
|
|
if (ret == 0)
|
|
|
return 0;
|
|
@@ -1705,6 +1704,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
|
|
|
void *file)
|
|
|
{
|
|
|
struct comedi_subdevice *s;
|
|
|
+ int ret;
|
|
|
|
|
|
if (arg >= dev->n_subdevices)
|
|
|
return -EINVAL;
|
|
@@ -1721,7 +1721,11 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
|
|
|
if (s->busy != file)
|
|
|
return -EBUSY;
|
|
|
|
|
|
- return do_cancel(dev, s);
|
|
|
+ ret = do_cancel(dev, s);
|
|
|
+ if (comedi_get_subdevice_runflags(s) & SRF_USER)
|
|
|
+ wake_up_interruptible(&s->async->wait_head);
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2053,11 +2057,13 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
|
|
|
|
|
|
if (!comedi_is_subdevice_running(s)) {
|
|
|
if (count == 0) {
|
|
|
+ mutex_lock(&dev->mutex);
|
|
|
if (comedi_is_subdevice_in_error(s))
|
|
|
retval = -EPIPE;
|
|
|
else
|
|
|
retval = 0;
|
|
|
do_become_nonbusy(dev, s);
|
|
|
+ mutex_unlock(&dev->mutex);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -2156,11 +2162,13 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
|
|
|
|
|
|
if (n == 0) {
|
|
|
if (!comedi_is_subdevice_running(s)) {
|
|
|
+ mutex_lock(&dev->mutex);
|
|
|
do_become_nonbusy(dev, s);
|
|
|
if (comedi_is_subdevice_in_error(s))
|
|
|
retval = -EPIPE;
|
|
|
else
|
|
|
retval = 0;
|
|
|
+ mutex_unlock(&dev->mutex);
|
|
|
break;
|
|
|
}
|
|
|
if (file->f_flags & O_NONBLOCK) {
|
|
@@ -2198,9 +2206,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
|
|
|
buf += n;
|
|
|
break; /* makes device work like a pipe */
|
|
|
}
|
|
|
- if (comedi_is_subdevice_idle(s) &&
|
|
|
- async->buf_read_count - async->buf_write_count == 0) {
|
|
|
- do_become_nonbusy(dev, s);
|
|
|
+ if (comedi_is_subdevice_idle(s)) {
|
|
|
+ mutex_lock(&dev->mutex);
|
|
|
+ if (async->buf_read_count - async->buf_write_count == 0)
|
|
|
+ do_become_nonbusy(dev, s);
|
|
|
+ mutex_unlock(&dev->mutex);
|
|
|
}
|
|
|
set_current_state(TASK_RUNNING);
|
|
|
remove_wait_queue(&async->wait_head, &wait);
|