kfusd/kfusd.c
static ssize_t fusd_process_write(struct file *file,
                                  const char *user_msg_buffer, size_t user_msg_len,
                                  const char *user_data_buffer, size_t user_data_len)
{
	fusd_dev_t *fusd_dev;
	fusd_msg_t *msg = NULL;
	int retval = 0;
	int yield = 0;

	GET_FUSD_DEV(file->private_data, fusd_dev);
	LOCK_FUSD_DEV(fusd_dev);

	/* get the header from userspace (first make sure there's enough data) */
	if (user_msg_len != sizeof(fusd_msg_t)) {
		RDEBUG(6, "control channel got bad write of %d bytes (wanted %d)",
		       (int) user_msg_len, (int) sizeof(fusd_msg_t));
		retval = -EINVAL;
		goto out_no_free;
	}
	if ((msg = KMALLOC(sizeof(fusd_msg_t), GFP_KERNEL)) == NULL) {
		retval = -ENOMEM;
		RDEBUG(1, "yikes!  kernel can't allocate memory");
		goto out;
	}
	memset(msg, 0, sizeof(fusd_msg_t));

	if (copy_from_user(msg, user_msg_buffer, sizeof(fusd_msg_t))) {
		retval = -EFAULT;
		goto out;
	}
	msg->data = NULL; /* pointers from userspace have no meaning */

	/* check the magic number before acting on the message at all */
	if (msg->magic != FUSD_MSG_MAGIC) {
		RDEBUG(2, "got invalid magic number on /dev/fusd write from pid %d",
		       current->pid);
		retval = -EIO;
		goto out;
	}

	/* now get data portion of the message */
	if (user_data_len < 0 || user_data_len > MAX_RW_SIZE) {
		RDEBUG(2, "fusd_process_write: got invalid length %d", (int) user_data_len);
		retval = -EINVAL;
		goto out;
	}
	if (msg->datalen != user_data_len) {
		RDEBUG(2, "%s : msg->datalen(%d) != user_data_len(%d), sigh!", __func__,
		       msg->datalen, (int) user_data_len);
		retval = -EINVAL;
		goto out;
	}
	if (user_data_len > 0) {
		if (user_data_buffer == NULL) {
			RDEBUG(2, "msg->datalen and no data buffer, sigh!");
			retval = -EINVAL;
			goto out;
		}
		if ((msg->data = VMALLOC(user_data_len)) == NULL) {
			retval = -ENOMEM;
			RDEBUG(1, "yikes!  kernel can't allocate memory");
			goto out;
		}
		if (copy_from_user(msg->data, user_data_buffer, user_data_len)) {
			retval = -EFAULT;
			goto out;
		}
	}

	/* before device registration, the only command allowed is 'register'. */
	/*
	if (!fusd_dev->handle && msg->cmd != FUSD_REGISTER_DEVICE) {
	  RDEBUG(2, "got a message other than 'register' on a new device!");
	  retval = -EINVAL;
	  goto out;
	}
	 */

	/* now dispatch the command to the appropriate handler */
	switch (msg->cmd) {
		case FUSD_REGISTER_DEVICE:
			retval = fusd_register_device(fusd_dev, msg->parm.register_msg);
			goto out;
			break;
		case FUSD_FOPS_REPLY:
			/* if reply is successful, DO NOT free the message */
			if ((retval = fusd_fops_reply(fusd_dev, msg)) == 0) {
				yield = 1;
				goto out_no_free;
			}
			break;
		case FUSD_FOPS_NONBLOCK_REPLY:
			switch (msg->subcmd) {
				case FUSD_POLL_DIFF:
					retval = fusd_polldiff_reply(fusd_dev, msg);
					break;
				default:
					RDEBUG(2, "fusd_fops_nonblock got unknown subcmd %d", msg->subcmd);
					retval = -EINVAL;
			}
			break;
		default:
			RDEBUG(2, "warning: unknown message type of %d received!", msg->cmd);
			retval = -EINVAL;
			goto out;
			break;
	}


out:
	if (msg && msg->data) {
		VFREE(msg->data);
		msg->data = NULL;
	}
	if (msg != NULL) {
		KFREE(msg);
		msg = NULL;
	}

out_no_free:

	/* the functions we call indicate success by returning 0.  we
	 * convert that into a success indication by changing the retval to
	 * the length of the write. */
	if (retval == 0)
		retval = user_data_len + user_msg_len;

	UNLOCK_FUSD_DEV(fusd_dev);

	/* if we successfully completed someone's syscall, yield the
	 * processor to them immediately as a throughput optimization.  we
	 * also hope that in the case of bulk data transfer, their next
	 * syscall will come in before we are scheduled again. */
	if (yield) {
#ifdef SCHED_YIELD
		current->policy |= SCHED_YIELD;
#endif
		schedule();
	}

	return retval;

zombie_dev:
invalid_dev:
	RDEBUG(1, "fusd_process_write: got invalid device!");
	return -EPIPE;
}
/*
 * This function processes messages coming from userspace device drivers
 * (i.e., writes to the /dev/fusd control channel.)
 */
This function processes messages coming from userspace device drivers
This function processes messages coming from userspace device drivers
static ssize_t fusd_process_write(struct file *file,
                                  const char *user_msg_buffer, size_t user_msg_len,
                                  const char *user_data_buffer, size_t user_data_len)
{
	fusd_dev_t *fusd_dev;
	fusd_msg_t *msg = NULL;
	int retval = 0;
	int yield = 0;
	GET_FUSD_DEV(file->private_data, fusd_dev);
	LOCK_FUSD_DEV(fusd_dev);
	if (user_msg_len != sizeof(fusd_msg_t)) {
		RDEBUG(6, "control channel got bad write of %d bytes (wanted %d)",
		       (int) user_msg_len, (int) sizeof(fusd_msg_t));
		retval = -EINVAL;
		goto out_no_free;
	}
	if ((msg = KMALLOC(sizeof(fusd_msg_t), GFP_KERNEL)) == NULL) {
		retval = -ENOMEM;
		RDEBUG(1, "yikes!  kernel can't allocate memory");
		goto out;
	}
	memset(msg, 0, sizeof(fusd_msg_t));
	if (copy_from_user(msg, user_msg_buffer, sizeof(fusd_msg_t))) {
		retval = -EFAULT;
		goto out;
	}
	msg->data = NULL; 
	if (msg->magic != FUSD_MSG_MAGIC) {
		RDEBUG(2, "got invalid magic number on /dev/fusd write from pid %d",
		       current->pid);
		retval = -EIO;
		goto out;
	}
	if (user_data_len < 0 || user_data_len > MAX_RW_SIZE) {
		RDEBUG(2, "fusd_process_write: got invalid length %d", (int) user_data_len);
		retval = -EINVAL;
		goto out;
	}
	if (msg->datalen != user_data_len) {
		RDEBUG(2, "%s : msg->datalen(%d) != user_data_len(%d), sigh!", __func__,
		       msg->datalen, (int) user_data_len);
		retval = -EINVAL;
		goto out;
	}
	if (user_data_len > 0) {
		if (user_data_buffer == NULL) {
			RDEBUG(2, "msg->datalen and no data buffer, sigh!");
			retval = -EINVAL;
			goto out;
		}
		if ((msg->data = VMALLOC(user_data_len)) == NULL) {
			retval = -ENOMEM;
			RDEBUG(1, "yikes!  kernel can't allocate memory");
			goto out;
		}
		if (copy_from_user(msg->data, user_data_buffer, user_data_len)) {
			retval = -EFAULT;
			goto out;
		}
	}
	switch (msg->cmd) {
		case FUSD_REGISTER_DEVICE:
			retval = fusd_register_device(fusd_dev, msg->parm.register_msg);
			goto out;
			break;
		case FUSD_FOPS_REPLY:
			if ((retval = fusd_fops_reply(fusd_dev, msg)) == 0) {
				yield = 1;
				goto out_no_free;
			}
			break;
		case FUSD_FOPS_NONBLOCK_REPLY:
			switch (msg->subcmd) {
				case FUSD_POLL_DIFF:
					retval = fusd_polldiff_reply(fusd_dev, msg);
					break;
				default:
					RDEBUG(2, "fusd_fops_nonblock got unknown subcmd %d", msg->subcmd);
					retval = -EINVAL;
			}
			break;
		default:
			RDEBUG(2, "warning: unknown message type of %d received!", msg->cmd);
			retval = -EINVAL;
			goto out;
			break;
	}
out:
	if (msg && msg->data) {
		VFREE(msg->data);
		msg->data = NULL;
	}
	if (msg != NULL) {
		KFREE(msg);
		msg = NULL;
	}
out_no_free:
	if (retval == 0)
		retval = user_data_len + user_msg_len;
	UNLOCK_FUSD_DEV(fusd_dev);
	if (yield) {
#ifdef SCHED_YIELD
		current->policy |= SCHED_YIELD;
#endif
		schedule();
	}
	return retval;
zombie_dev:
invalid_dev:
	RDEBUG(1, "fusd_process_write: got invalid device!");
	return -EPIPE;
}
static ssize_t fusd_process_write ( struct file * file , const char * user_msg_buffer , size_t user_msg_len , const char * user_data_buffer , size_t user_data_len ) { fusd_dev_t * fusd_dev ; fusd_msg_t * msg = NULL ; int retval = 0 ; int yield = 0 ; GET_FUSD_DEV ( file -> private_data , fusd_dev ) ; LOCK_FUSD_DEV ( fusd_dev ) ; if ( user_msg_len != sizeof ( fusd_msg_t ) ) { RDEBUG ( 6 , " " , ( int ) user_msg_len , ( int ) sizeof ( fusd_msg_t ) ) ; retval = - EINVAL ; goto out_no_free ; } if ( ( msg = KMALLOC ( sizeof ( fusd_msg_t ) , GFP_KERNEL ) ) == NULL ) { retval = - ENOMEM ; RDEBUG ( 1 , " " ) ; goto out ; } memset ( msg , 0 , sizeof ( fusd_msg_t ) ) ; if ( copy_from_user ( msg , user_msg_buffer , sizeof ( fusd_msg_t ) ) ) { retval = - EFAULT ; goto out ; } msg -> data = NULL ; if ( msg -> magic != FUSD_MSG_MAGIC ) { RDEBUG ( 2 , " " , current -> pid ) ; retval = - EIO ; goto out ; } if ( user_data_len < 0 || user_data_len > MAX_RW_SIZE ) { RDEBUG ( 2 , " " , ( int ) user_data_len ) ; retval = - EINVAL ; goto out ; } if ( msg -> datalen != user_data_len ) { RDEBUG ( 2 , " " , __func__ , msg -> datalen , ( int ) user_data_len ) ; retval = - EINVAL ; goto out ; } if ( user_data_len > 0 ) { if ( user_data_buffer == NULL ) { RDEBUG ( 2 , " " ) ; retval = - EINVAL ; goto out ; } if ( ( msg -> data = VMALLOC ( user_data_len ) ) == NULL ) { retval = - ENOMEM ; RDEBUG ( 1 , " " ) ; goto out ; } if ( copy_from_user ( msg -> data , user_data_buffer , user_data_len ) ) { retval = - EFAULT ; goto out ; } } switch ( msg -> cmd ) { case FUSD_REGISTER_DEVICE : retval = fusd_register_device ( fusd_dev , msg -> parm . register_msg ) ; goto out ; break ; case FUSD_FOPS_REPLY : if ( ( retval = fusd_fops_reply ( fusd_dev , msg ) ) == 0 ) { yield = 1 ; goto out_no_free ; } break ; case FUSD_FOPS_NONBLOCK_REPLY : switch ( msg -> subcmd ) { case FUSD_POLL_DIFF : retval = fusd_polldiff_reply ( fusd_dev , msg ) ; break ; default : RDEBUG ( 2 , " " , msg -> subcmd ) ; retval = - EINVAL ; } break ; default : RDEBUG ( 2 , " " , msg -> cmd ) ; retval = - EINVAL ; goto out ; break ; } out : if ( msg && msg -> data ) { VFREE ( msg -> data ) ; msg -> data = NULL ; } if ( msg != NULL ) { KFREE ( msg ) ; msg = NULL ; } out_no_free : if ( retval == 0 ) retval = user_data_len + user_msg_len ; UNLOCK_FUSD_DEV ( fusd_dev ) ; if ( yield ) { #ifdef SCHED_YIELD current -> policy |= SCHED_YIELD ; #endif schedule ( ) ; } return retval ; zombie_dev : invalid_dev : RDEBUG ( 1 , " " ) ; return - EPIPE ; }
This function processes messages coming from userspace device drivers
 (i.e., writes to the /dev/fusd control channel.)
This function processes messages coming from userspace device drivers ( i . e . writes to the / dev / fusd control channel . )
/* get the header from userspace (first make sure there's enough data) */ /* pointers from userspace have no meaning */ /* check the magic number before acting on the message at all */ /* now get data portion of the message */ /* before device registration, the only command allowed is 'register'. */ /*
	if (!fusd_dev->handle && msg->cmd != FUSD_REGISTER_DEVICE) {
	  RDEBUG(2, "got a message other than 'register' on a new device!");
	  retval = -EINVAL;
	  goto out;
	}
	 */ /* now dispatch the command to the appropriate handler */ /* if reply is successful, DO NOT free the message */ /* the functions we call indicate success by returning 0.  we
	 * convert that into a success indication by changing the retval to
	 * the length of the write. */ /* if we successfully completed someone's syscall, yield the
	 * processor to them immediately as a throughput optimization.  we
	 * also hope that in the case of bulk data transfer, their next
	 * syscall will come in before we are scheduled again. */