[PATCH 7/9] VC04_SERVICES: Add compat ioctl handler for "dequeue message"

Michael Zoran mzoran at crowfest.net
Wed Jan 18 07:04:51 PST 2017


Add compat handler for "dequeue messagen" ioctl and move
parts in common with the regular ioctl to vchiq_ioctl_dequeue_message.

Signed-off-by: Michael Zoran <mzoran at crowfest.net>
---
 .../vc04_services/interface/vchiq_arm/vchiq_arm.c  | 168 ++++++++++++---------
 1 file changed, 100 insertions(+), 68 deletions(-)

diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index d9f3b0b34a95..98a67c434cfd 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -837,6 +837,83 @@ vchiq_ioctl_put_msgbuf_count(unsigned long arg,
 			      sizeof(msgbufcount));
 }
 
+static long
+vchiq_ioctl_dequeue_message(VCHIQ_INSTANCE_T instance,
+			    VCHIQ_DEQUEUE_MESSAGE_T *args,
+			    VCHIQ_SERVICE_T **service)
+{
+	USER_SERVICE_T *user_service;
+	VCHIQ_HEADER_T *header;
+	long ret = 0;
+
+	DEBUG_INITIALISE(g_state.local)
+
+	*service = find_service_for_instance(instance, args->handle);
+	if (!*service)
+		return -EINVAL;
+
+	user_service = (USER_SERVICE_T *)(*service)->base.userdata;
+	if (user_service->is_vchi == 0)
+		return -EINVAL;
+
+	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);
+			return -EWOULDBLOCK;
+		}
+
+		user_service->dequeue_pending = 1;
+		do {
+			spin_unlock(&msg_queue_spinlock);
+			DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
+			if (down_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)
+			return ret;
+	}
+
+	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);
+
+	up(&user_service->remove_event);
+
+	if (!header)
+		return -ENOTCONN;
+
+	if (header->size > args->bufsize) {
+		vchiq_log_error(vchiq_arm_log_level,
+				"header %pK: bufsize %x < size %x",
+				header, args->bufsize, header->size);
+		WARN(1, "invalid size\n");
+		return -EMSGSIZE;
+	}
+
+	if (args->buf)
+		if (copy_to_user((void __user *)args->buf,
+				 header->data,
+				 header->size))
+			return -EFAULT;
+
+	ret = header->size;
+	vchiq_release_message((*service)->handle, header);
+
+	return ret;
+}
+
 /****************************************************************************
 *
 *   vchiq_ioctl
@@ -1101,8 +1178,6 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 	case VCHIQ_IOC_DEQUEUE_MESSAGE: {
 		VCHIQ_DEQUEUE_MESSAGE_T args;
-		USER_SERVICE_T *user_service;
-		VCHIQ_HEADER_T *header;
 
 		DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
 		if (copy_from_user
@@ -1111,74 +1186,9 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 			ret = -EFAULT;
 			break;
 		}
-		service = find_service_for_instance(instance, args.handle);
-		if (!service) {
-			ret = -EINVAL;
-			break;
-		}
-		user_service = (USER_SERVICE_T *)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 (down_interruptible(
-					&user_service->insert_event) != 0) {
-					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 &
-			(MSG_QUEUE_SIZE - 1)];
-		user_service->msg_remove++;
-		spin_unlock(&msg_queue_spinlock);
+		ret = vchiq_ioctl_dequeue_message(instance, &args, &service);
 
-		up(&user_service->remove_event);
-		if (header == NULL)
-			ret = -ENOTCONN;
-		else if (header->size <= args.bufsize) {
-			/* Copy to user space if msgbuf is not NULL */
-			if ((args.buf == NULL) ||
-				(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;
 
@@ -1515,6 +1525,27 @@ vchiq_ioctl_compat_internal(
 						   vchiq_ioctl_compat_put_msgbuf_count);
 	} break;
 
+	case VCHIQ_IOC_DEQUEUE_MESSAGE32: {
+		VCHIQ_DEQUEUE_MESSAGE_T args;
+		struct vchiq_dequeue_message32 args32;
+
+		DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
+		if (copy_from_user(&args32, (const void __user *)arg,
+				   sizeof(args32))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		args.handle	= args32.handle;
+		args.blocking	= args32.blocking;
+		args.bufsize	= args32.bufsize;
+		args.buf	= compat_ptr(args32.buf);
+
+		ret = vchiq_ioctl_dequeue_message(instance, &args, &service);
+
+		DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
+	} break;
+
 	default:
 		ret = -ENOTTY;
 		break;
@@ -1560,6 +1591,7 @@ vchiq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 	case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
 	case VCHIQ_IOC_QUEUE_BULK_RECEIVE32:
 	case VCHIQ_IOC_AWAIT_COMPLETION32:
+	case VCHIQ_IOC_DEQUEUE_MESSAGE32:
 		return vchiq_ioctl_compat_internal(file, cmd, arg);
 	default:
 		return vchiq_ioctl(file, cmd, arg);
-- 
2.11.0




More information about the linux-rpi-kernel mailing list