if (read_cmd.completed_transfer_count > read_cmd.requested_transfer_count)
return -EINVAL;
- desc = handle_to_descriptor(file_priv, read_cmd.handle);
- if (!desc)
- return -EINVAL;
-
if (WARN_ON_ONCE(sizeof(userbuf) > sizeof(read_cmd.buffer_ptr)))
return -EFAULT;
if (!access_ok(userbuf, remain))
return -EFAULT;
+ /* Lock descriptors to prevent concurrent close from freeing descriptor */
+ if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
+ return -ERESTARTSYS;
+ desc = handle_to_descriptor(file_priv, read_cmd.handle);
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
+
atomic_set(&desc->io_in_progress, 1);
/* Read buffer loads till we fill the user supplied buffer */
retval = copy_to_user((void __user *)arg, &read_cmd, sizeof(read_cmd));
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
if (retval)
if (cmd.completed_transfer_count > cmd.requested_transfer_count)
return -EINVAL;
- desc = handle_to_descriptor(file_priv, cmd.handle);
- if (!desc)
- return -EINVAL;
-
userbuf = (u8 __user *)(unsigned long)cmd.buffer_ptr;
userbuf += cmd.completed_transfer_count;
if (!access_ok(userbuf, remain))
return -EFAULT;
+ /* Lock descriptors to prevent concurrent close from freeing descriptor */
+ if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
+ return -ERESTARTSYS;
+ desc = handle_to_descriptor(file_priv, cmd.handle);
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
+
/*
* Write buffer loads till we empty the user supplied buffer.
* Call drivers at least once, even if remain is zero, in
userbuf += bytes_written;
if (retval < 0) {
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
break;
*/
if (!no_clear_io_in_prog || fault)
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
if (fault)
if (write_cmd.completed_transfer_count > write_cmd.requested_transfer_count)
return -EINVAL;
- desc = handle_to_descriptor(file_priv, write_cmd.handle);
- if (!desc)
- return -EINVAL;
-
userbuf = (u8 __user *)(unsigned long)write_cmd.buffer_ptr;
userbuf += write_cmd.completed_transfer_count;
if (!access_ok(userbuf, remain))
return -EFAULT;
+ /* Lock descriptors to prevent concurrent close from freeing descriptor */
+ if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
+ return -ERESTARTSYS;
+ desc = handle_to_descriptor(file_priv, write_cmd.handle);
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
+
atomic_set(&desc->io_in_progress, 1);
/* Write buffer loads till we empty the user supplied buffer */
fault = copy_to_user((void __user *)arg, &write_cmd, sizeof(write_cmd));
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
if (fault)
{
struct gpib_close_dev_ioctl cmd;
struct gpib_file_private *file_priv = filep->private_data;
+ struct gpib_descriptor *desc;
+ unsigned int pad;
+ int sad;
int retval;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
if (cmd.handle >= GPIB_MAX_NUM_DESCRIPTORS)
return -EINVAL;
- if (!file_priv->descriptors[cmd.handle])
- return -EINVAL;
- retval = decrement_open_device_count(board, &board->device_list,
- file_priv->descriptors[cmd.handle]->pad,
- file_priv->descriptors[cmd.handle]->sad);
- if (retval < 0)
- return retval;
-
- kfree(file_priv->descriptors[cmd.handle]);
+ mutex_lock(&file_priv->descriptors_mutex);
+ desc = file_priv->descriptors[cmd.handle];
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ if (atomic_read(&desc->descriptor_busy)) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EBUSY;
+ }
+ /* Remove from table while holding lock to prevent new IO from starting */
file_priv->descriptors[cmd.handle] = NULL;
+ pad = desc->pad;
+ sad = desc->sad;
+ mutex_unlock(&file_priv->descriptors_mutex);
- return 0;
+ retval = decrement_open_device_count(board, &board->device_list, pad, sad);
+
+ kfree(desc);
+ return retval;
}
static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg)
if (retval)
return -EFAULT;
+ /*
+ * Lock descriptors to prevent concurrent close from freeing
+ * descriptor. ibwait() releases big_gpib_mutex when wait_mask
+ * is non-zero, so desc must be pinned with descriptor_busy.
+ */
+ mutex_lock(&file_priv->descriptors_mutex);
desc = handle_to_descriptor(file_priv, wait_cmd.handle);
- if (!desc)
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
retval = ibwait(board, wait_cmd.wait_mask, wait_cmd.clear_mask,
wait_cmd.set_mask, &wait_cmd.ibsta, wait_cmd.usec_timeout, desc);
+
+ atomic_dec(&desc->descriptor_busy);
+
if (retval < 0)
return retval;
desc->is_board = 0;
desc->autopoll_enabled = 0;
atomic_set(&desc->io_in_progress, 0);
+ atomic_set(&desc->descriptor_busy, 0);
}
int gpib_register_driver(struct gpib_interface *interface, struct module *provider_module)