Commit f618affa authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Greg Kroah-Hartman

staging: vchiq: convert compat dequeue_message

Split out the ioctl implementation for VCHIQ_IOC_DEQUEUE_MESSAGE
into a separate function so it can be shared with the compat
implementation.
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/r/20200918095441.1446041-4-arnd@arndb.deSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9f9caab9
...@@ -858,6 +858,86 @@ static int vchiq_ioc_create_service(struct vchiq_instance *instance, ...@@ -858,6 +858,86 @@ static int vchiq_ioc_create_service(struct vchiq_instance *instance,
return 0; return 0;
} }
static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
struct vchiq_dequeue_message *args)
{
struct user_service *user_service;
struct vchiq_service *service;
struct vchiq_header *header;
int ret;
DEBUG_INITIALISE(g_state.local)
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
service = find_service_for_instance(instance, args->handle);
if (!service)
return -EINVAL;
user_service = (struct user_service *)service->base.userdata;
if (user_service->is_vchi == 0) {
ret = -EINVAL;
goto out;
}
spin_lock(&msg_queue_spinlock);
if (user_service->msg_remove == user_service->msg_insert) {
if (!args->blocking) {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
ret = -EWOULDBLOCK;
goto out;
}
user_service->dequeue_pending = 1;
ret = 0;
do {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
if (wait_for_completion_interruptible(
&user_service->insert_event)) {
vchiq_log_info(vchiq_arm_log_level,
"DEQUEUE_MESSAGE interrupted");
ret = -EINTR;
break;
}
spin_lock(&msg_queue_spinlock);
} while (user_service->msg_remove ==
user_service->msg_insert);
if (ret)
goto out;
}
BUG_ON((int)(user_service->msg_insert -
user_service->msg_remove) < 0);
header = user_service->msg_queue[user_service->msg_remove &
(MSG_QUEUE_SIZE - 1)];
user_service->msg_remove++;
spin_unlock(&msg_queue_spinlock);
complete(&user_service->remove_event);
if (!header) {
ret = -ENOTCONN;
} else if (header->size <= args->bufsize) {
/* Copy to user space if msgbuf is not NULL */
if (!args->buf || (copy_to_user((void __user *)args->buf,
header->data, header->size) == 0)) {
ret = header->size;
vchiq_release_message(service->handle, header);
} else
ret = -EFAULT;
} else {
vchiq_log_error(vchiq_arm_log_level,
"header %pK: bufsize %x < size %x",
header, args->bufsize, header->size);
WARN(1, "invalid size\n");
ret = -EMSGSIZE;
}
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
out:
unlock_service(service);
return ret;
}
/**************************************************************************** /****************************************************************************
* *
* vchiq_ioctl * vchiq_ioctl
...@@ -1287,84 +1367,14 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -1287,84 +1367,14 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case VCHIQ_IOC_DEQUEUE_MESSAGE: { case VCHIQ_IOC_DEQUEUE_MESSAGE: {
struct vchiq_dequeue_message args; struct vchiq_dequeue_message args;
struct user_service *user_service;
struct vchiq_header *header;
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
if (copy_from_user(&args, (const void __user *)arg, if (copy_from_user(&args, (const void __user *)arg,
sizeof(args))) { sizeof(args))) {
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
service = find_service_for_instance(instance, args.handle);
if (!service) {
ret = -EINVAL;
break;
}
user_service = (struct user_service *)service->base.userdata;
if (user_service->is_vchi == 0) {
ret = -EINVAL;
break;
}
spin_lock(&msg_queue_spinlock);
if (user_service->msg_remove == user_service->msg_insert) {
if (!args.blocking) {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
ret = -EWOULDBLOCK;
break;
}
user_service->dequeue_pending = 1;
do {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
if (wait_for_completion_interruptible(
&user_service->insert_event)) {
vchiq_log_info(vchiq_arm_log_level,
"DEQUEUE_MESSAGE interrupted");
ret = -EINTR;
break;
}
spin_lock(&msg_queue_spinlock);
} while (user_service->msg_remove ==
user_service->msg_insert);
if (ret)
break;
}
BUG_ON((int)(user_service->msg_insert -
user_service->msg_remove) < 0);
header = user_service->msg_queue[user_service->msg_remove & ret = vchiq_ioc_dequeue_message(instance, &args);
(MSG_QUEUE_SIZE - 1)];
user_service->msg_remove++;
spin_unlock(&msg_queue_spinlock);
complete(&user_service->remove_event);
if (!header)
ret = -ENOTCONN;
else if (header->size <= args.bufsize) {
/* Copy to user space if msgbuf is not NULL */
if (!args.buf ||
(copy_to_user((void __user *)args.buf,
header->data,
header->size) == 0)) {
ret = header->size;
vchiq_release_message(
service->handle,
header);
} else
ret = -EFAULT;
} else {
vchiq_log_error(vchiq_arm_log_level,
"header %pK: bufsize %x < size %x",
header, args.bufsize, header->size);
WARN(1, "invalid size\n");
ret = -EMSGSIZE;
}
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
} break; } break;
case VCHIQ_IOC_GET_CLIENT_ID: { case VCHIQ_IOC_GET_CLIENT_ID: {
...@@ -1824,28 +1834,22 @@ struct vchiq_dequeue_message32 { ...@@ -1824,28 +1834,22 @@ struct vchiq_dequeue_message32 {
static long static long
vchiq_compat_ioctl_dequeue_message(struct file *file, vchiq_compat_ioctl_dequeue_message(struct file *file,
unsigned int cmd, unsigned int cmd,
unsigned long arg) struct vchiq_dequeue_message32 __user *arg)
{ {
struct vchiq_dequeue_message __user *args;
struct vchiq_dequeue_message32 args32; struct vchiq_dequeue_message32 args32;
struct vchiq_dequeue_message args;
args = compat_alloc_user_space(sizeof(*args)); if (copy_from_user(&args32, arg, sizeof(args32)))
if (!args)
return -EFAULT;
if (copy_from_user(&args32,
(struct vchiq_dequeue_message32 __user *)arg,
sizeof(args32)))
return -EFAULT; return -EFAULT;
if (put_user(args32.handle, &args->handle) || args = (struct vchiq_dequeue_message) {
put_user(args32.blocking, &args->blocking) || .handle = args32.handle,
put_user(args32.bufsize, &args->bufsize) || .blocking = args32.blocking,
put_user(compat_ptr(args32.buf), &args->buf)) .bufsize = args32.bufsize,
return -EFAULT; .buf = compat_ptr(args32.buf),
};
return vchiq_ioctl(file, VCHIQ_IOC_DEQUEUE_MESSAGE, return vchiq_ioc_dequeue_message(file->private_data, &args);
(unsigned long)args);
} }
struct vchiq_get_config32 { struct vchiq_get_config32 {
...@@ -1893,7 +1897,7 @@ vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -1893,7 +1897,7 @@ vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case VCHIQ_IOC_AWAIT_COMPLETION32: case VCHIQ_IOC_AWAIT_COMPLETION32:
return vchiq_compat_ioctl_await_completion(file, cmd, arg); return vchiq_compat_ioctl_await_completion(file, cmd, arg);
case VCHIQ_IOC_DEQUEUE_MESSAGE32: case VCHIQ_IOC_DEQUEUE_MESSAGE32:
return vchiq_compat_ioctl_dequeue_message(file, cmd, arg); return vchiq_compat_ioctl_dequeue_message(file, cmd, argp);
case VCHIQ_IOC_GET_CONFIG32: case VCHIQ_IOC_GET_CONFIG32:
return vchiq_compat_ioctl_get_config(file, cmd, argp); return vchiq_compat_ioctl_get_config(file, cmd, argp);
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment