[PATCH 5/9] VC04_SERVICES: Add compat ioctl handler for "queue bulk"

Dan Carpenter dan.carpenter at oracle.com
Thu Jan 19 01:30:43 PST 2017


Same stuff, break this into two patches.

On Wed, Jan 18, 2017 at 07:04:49AM -0800, Michael Zoran wrote:
> Add compat handler for "queue bulk" ioctls and move
> parts in common with the regular ioctls to vchiq_ioctl_queue_bulk
> 
> Signed-off-by: Michael Zoran <mzoran at crowfest.net>
> ---
>  .../vc04_services/interface/vchiq_arm/vchiq_arm.c  | 206 ++++++++++++++-------
>  1 file changed, 141 insertions(+), 65 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 1c0afa318036..7067bd3f4bd5 100644
> --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> @@ -572,6 +572,87 @@ vchiq_ioctl_create_service(VCHIQ_INSTANCE_T instance,
>  	return 0;
>  }
>  
> +static long
> +vchiq_ioctl_queue_bulk(VCHIQ_INSTANCE_T instance,
> +		       VCHIQ_QUEUE_BULK_TRANSFER_T *args,
> +		       VCHIQ_BULK_DIR_T dir,
> +		       VCHIQ_STATUS_T *status,
> +		       bool *needs_ret_mode_waiting)
> +{
> +	struct bulk_waiter_node *waiter = NULL;

Add a blank line.

> +	*needs_ret_mode_waiting = false;
> +
> +	if (args->mode == VCHIQ_BULK_MODE_BLOCKING) {
> +		waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
> +
> +		if (!waiter)
> +			return -ENOMEM;
> +
> +		args->userdata = &waiter->bulk_waiter;
> +	} else if (args->mode == VCHIQ_BULK_MODE_WAITING) {
> +		struct list_head *pos;
> +
> +		mutex_lock(&instance->bulk_waiter_list_mutex);
> +		list_for_each(pos, &instance->bulk_waiter_list) {
> +			if (list_entry(pos, struct bulk_waiter_node,
> +				       list)->pid == current->pid) {
> +					waiter = list_entry(pos,
> +							    struct bulk_waiter_node,
> +							    list);
> +					list_del(pos);
> +					break;
> +				}
> +		}

There are some extra tabs there.  Also just flip the condition around.
Maybe use list_for_each_entry()?

		if (list_entry(pos, struct bulk_waiter_node, ist)->pid !=
		    current->pid)
			continue;

		waiter = list_entry(pos, struct bulk_waiter_node, list);
		list_del(pos);
		break;
	}

> +
> +		mutex_unlock(&instance->bulk_waiter_list_mutex);
> +		if (!waiter) {
> +			vchiq_log_error(vchiq_arm_log_level,
> +					"no bulk_waiter found for pid %d",
> +					current->pid);
> +			return -ESRCH;
> +		}
> +
> +		vchiq_log_info(vchiq_arm_log_level,
> +			       "found bulk_waiter %pK for pid %d", waiter,
> +			       current->pid);

This printk looks like it could get annoying.  Shouldn't it be a debug
or something?

> +		args->userdata = &waiter->bulk_waiter;
> +	}
> +
> +	*status = vchiq_bulk_transfer(args->handle,
> +			 VCHI_MEM_HANDLE_INVALID,
> +			 args->data, args->size,
> +			 args->userdata, args->mode,
> +			 dir);
> +
> +	if (!waiter)
> +		return 0;
> +
> +	if ((*status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
> +	    !waiter->bulk_waiter.bulk) {
> +		if (waiter->bulk_waiter.bulk) {
> +			/*
> +			 * Cancel the signal when the transfer
> +			 * completes.
> +			 */
> +			spin_lock(&bulk_waiter_spinlock);
> +			waiter->bulk_waiter.bulk->userdata = NULL;
> +			spin_unlock(&bulk_waiter_spinlock);
> +		}
> +		kfree(waiter);

This kfree() looks mighty suspect.  ->mode == VCHIQ_BULK_MODE_WAITING?

> +	} else {
> +		*needs_ret_mode_waiting  = true;
> +		waiter->pid = current->pid;
> +		mutex_lock(&instance->bulk_waiter_list_mutex);
> +		list_add(&waiter->list, &instance->bulk_waiter_list);
> +		mutex_unlock(&instance->bulk_waiter_list_mutex);
> +		vchiq_log_info(vchiq_arm_log_level,
> +			       "saved bulk_waiter %pK for pid %d",
> +			       waiter, current->pid);

No kfree() on this path?  I will review this properly in v2.


> +	}
> +
> +	return 0;
> +}
> +
>  /****************************************************************************
>  *
>  *   vchiq_ioctl
> @@ -774,7 +855,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  	case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
>  	case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
>  		VCHIQ_QUEUE_BULK_TRANSFER_T args;
> -		struct bulk_waiter_node *waiter = NULL;
> +		bool needs_ret_mode_waiting = false;
>  		VCHIQ_BULK_DIR_T dir =
>  			(cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
>  			VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
> @@ -792,75 +873,21 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  			break;
>  		}
>  
> -		if (args.mode == VCHIQ_BULK_MODE_BLOCKING) {
> -			waiter = kzalloc(sizeof(struct bulk_waiter_node),
> -				GFP_KERNEL);
> -			if (!waiter) {
> -				ret = -ENOMEM;
> -				break;
> -			}
> -			args.userdata = &waiter->bulk_waiter;
> -		} else if (args.mode == VCHIQ_BULK_MODE_WAITING) {
> -			struct list_head *pos;
> -			mutex_lock(&instance->bulk_waiter_list_mutex);
> -			list_for_each(pos, &instance->bulk_waiter_list) {
> -				if (list_entry(pos, struct bulk_waiter_node,
> -					list)->pid == current->pid) {
> -					waiter = list_entry(pos,
> -						struct bulk_waiter_node,
> -						list);
> -					list_del(pos);
> -					break;
> -				}
> +		ret = vchiq_ioctl_queue_bulk(instance,
> +					     &args,
> +					     dir,
> +					     &status,
> +					     &needs_ret_mode_waiting);
>  
> -			}
> -			mutex_unlock(&instance->bulk_waiter_list_mutex);
> -			if (!waiter) {
> -				vchiq_log_error(vchiq_arm_log_level,
> -					"no bulk_waiter found for pid %d",
> -					current->pid);
> -				ret = -ESRCH;
> -				break;
> -			}
> -			vchiq_log_info(vchiq_arm_log_level,
> -				"found bulk_waiter %pK for pid %d", waiter,
> -				current->pid);
> -			args.userdata = &waiter->bulk_waiter;
> -		}
> -		status = vchiq_bulk_transfer
> -			(args.handle,
> -			 VCHI_MEM_HANDLE_INVALID,
> -			 args.data, args.size,
> -			 args.userdata, args.mode,
> -			 dir);
> -		if (!waiter)
> -			break;
> -		if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
> -			!waiter->bulk_waiter.bulk) {
> -			if (waiter->bulk_waiter.bulk) {
> -				/* Cancel the signal when the transfer
> -				** completes. */
> -				spin_lock(&bulk_waiter_spinlock);
> -				waiter->bulk_waiter.bulk->userdata = NULL;
> -				spin_unlock(&bulk_waiter_spinlock);
> -			}
> -			kfree(waiter);
> -		} else {
> +		if (needs_ret_mode_waiting) {
>  			const VCHIQ_BULK_MODE_T mode_waiting =
>  				VCHIQ_BULK_MODE_WAITING;
> -			waiter->pid = current->pid;
> -			mutex_lock(&instance->bulk_waiter_list_mutex);
> -			list_add(&waiter->list, &instance->bulk_waiter_list);
> -			mutex_unlock(&instance->bulk_waiter_list_mutex);
> -			vchiq_log_info(vchiq_arm_log_level,
> -				"saved bulk_waiter %pK for pid %d",
> -				waiter, current->pid);
>  
>  			if (copy_to_user((void __user *)
> -				&(((VCHIQ_QUEUE_BULK_TRANSFER_T __user *)
> -					arg)->mode),
> -				(const void *)&mode_waiting,
> -				sizeof(mode_waiting)) != 0)
> +					 &(((VCHIQ_QUEUE_BULK_TRANSFER_T __user *)
> +					 arg)->mode),
> +					(const void *)&mode_waiting,
> +					sizeof(mode_waiting)))
>  				ret = -EFAULT;

This stuff hurts my eye balls.  It turns out that the difference in
that wall of text is the extra tabs and we've removed a != 0.  Do that
in a different patch otherwise it just makes review painful.

>  		}
>  	} break;
> @@ -1306,6 +1333,53 @@ vchiq_ioctl_compat_internal(
>  						 elements, args32.count);
>  	} break;
>  
> +	case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
> +	case VCHIQ_IOC_QUEUE_BULK_RECEIVE32: {
> +		VCHIQ_QUEUE_BULK_TRANSFER_T args;
> +		struct vchiq_queue_bulk_transfer32 args32;
> +		bool needs_ret_mode_waiting = false;
> +		VCHIQ_BULK_DIR_T dir =
> +			(cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32) ?
> +			VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
> +
> +		if (copy_from_user
> +			(&args32, (const void __user *)arg,
> +			sizeof(args32))) {
> +			ret = -EFAULT;
> +			break;
> +		}
> +
> +		args.handle   = args32.handle;
> +		args.data     = compat_ptr(args32.data);
> +		args.size     = args32.size;
> +		args.userdata = compat_ptr(args32.userdata);
> +		args.mode     = args32.mode;
> +
> +		service = find_service_for_instance(instance, args.handle);
> +		if (!service) {
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		ret = vchiq_ioctl_queue_bulk(instance,
> +					     &args,
> +					     dir,
> +					     &status,
> +					     &needs_ret_mode_waiting);

I know that needs_ret_mode_waiting == 0 implies that ret == 0, but just
do the error handling first.

		if (ret)
			return ret;

> +
> +		if (needs_ret_mode_waiting) {
> +			const VCHIQ_BULK_MODE_T mode_waiting =
> +				VCHIQ_BULK_MODE_WAITING;
> +
> +			if (copy_to_user((void __user *)
> +					 &(((struct vchiq_queue_bulk_transfer32 __user *)
> +					 arg)->mode),
> +					(const void *)&mode_waiting,
> +					sizeof(mode_waiting)))
> +				ret = -EFAULT;
> +		}
> +	} break;
> +
>  	default:
>  		ret = -ENOTTY;
>  		break;
> @@ -1348,6 +1422,8 @@ vchiq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
>  	switch (cmd) {
>  	case VCHIQ_IOC_CREATE_SERVICE32:
>  	case VCHIQ_IOC_QUEUE_MESSAGE32:
> +	case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
> +	case VCHIQ_IOC_QUEUE_BULK_RECEIVE32:
>  		return vchiq_ioctl_compat_internal(file, cmd, arg);
>  	default:
>  		return vchiq_ioctl(file, cmd, arg);
> -- 
> 2.11.0
> 
> _______________________________________________
> devel mailing list
> devel at linuxdriverproject.org
> http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel



More information about the linux-rpi-kernel mailing list