kfusd/kfusd.c
static int fusd_fops_call_wait(fusd_file_t *fusd_file_arg,
                               fusd_msg_t **fusd_msg_reply, struct fusd_transaction *transaction)
{
	fusd_dev_t *fusd_dev;
	fusd_file_t *fusd_file;
	int retval;

	/* I check this just in case, shouldn't be necessary. */
	GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev);

	/* initialize first to tell callers there is no reply (yet) */
	if (fusd_msg_reply != NULL)
		*fusd_msg_reply = NULL;

	/*
	 * Now, lock the device, check for an incoming message, and sleep if
	 * there is not a message already waiting for us.  Note that we are
	 * unrolling the interruptible_sleep_on, as in the kernel's
	 * fs/pipe.c, to avoid race conditions between checking for the
	 * sleep condition and sleeping.
	 */
	LOCK_FUSD_DEV(fusd_dev);
	while (transaction->msg_in == NULL) {
		DECLARE_WAITQUEUE(wait, current);

		RDEBUG(10, "pid %d blocking on transid %ld", current->pid, transaction->transid);
		current->state = TASK_INTERRUPTIBLE;
		add_wait_queue(&fusd_file->file_wait, &wait);
		UNLOCK_FUSD_DEV(fusd_dev);
		UNLOCK_FUSD_FILE(fusd_file);

		schedule();
		remove_wait_queue(&fusd_file->file_wait, &wait);
		current->state = TASK_RUNNING;

		/*
		 * If we woke up due to a signal -- and not due to a reply message
		 * coming in -- then we are in some trouble.  The driver is already
		 * processing the request and might have changed some state that is
		 * hard to roll back.  So, we'll tell the process to restart the
		 * system call, and come back to this point when the system call is
		 * restarted.  We need to remember the PID to avoid confusion in
		 * case there is another process holding this file descriptor that
		 * is also trying to make a call.
		 */
		if (signal_pending(current)) {
			RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS",
			       current->pid);
			LOCK_FUSD_FILE(fusd_file);
			return -ERESTARTSYS;
		}

		LOCK_FUSD_FILE(fusd_file);
		/* re-lock the device, so we can do our msg_in check again */
		LOCK_FUSD_DEV(fusd_dev);
	}
	UNLOCK_FUSD_DEV(fusd_dev);

	/* ok - at this point we are awake due to a message received. */

	if (transaction->msg_in->cmd != FUSD_FOPS_REPLY ||
	    transaction->msg_in->subcmd != transaction->subcmd ||
	    transaction->msg_in->parm.fops_msg.transid != transaction->transid ||
	    transaction->msg_in->parm.fops_msg.fusd_file != fusd_file) {
		RDEBUG(2, "fusd_fops_call: invalid reply!");
		goto invalid_reply;
	}

	/* copy metadata back from userspace */
	fusd_file->file->f_flags = transaction->msg_in->parm.fops_msg.flags;
	fusd_file->private_data = transaction->msg_in->parm.fops_msg.private_info;
	/* note, changes to device_info are NO LONGER honored here */

	/* if everything's okay, return the return value.  if caller is
	 * willing to take responsibility for freeing the message itself, we
	 * return the message too. */
	retval = transaction->msg_in->parm.fops_msg.retval;
	if (fusd_msg_reply != NULL) {
		/* NOW TRANSFERRING RESPONSIBILITY FOR FREEING THIS DATA TO THE CALLER */
		*fusd_msg_reply = transaction->msg_in;
		transaction->msg_in = NULL;
	} else {
		/* free the message ourselves */
		free_fusd_msg(&transaction->msg_in);
	}

	/* success */
	fusd_cleanup_transaction(fusd_file, transaction);
	return retval;

invalid_reply:
	fusd_cleanup_transaction(fusd_file, transaction);
	return -EPIPE;

	/* bizarre errors go straight here */
invalid_dev:
invalid_file:
	RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!");
	return -EPIPE;

zombie_dev:
	RDEBUG(2, "fusd_fops_call: %s zombified while waiting for reply",
	       NAME(fusd_dev));
	return -EPIPE;
}
/*
 * fusd_fops_call_wait: wait for a driver to reply to a message
 *
 * NOTE - we are already holding the lock on fusd_file_arg when this
 * function is called, but NOT the lock on the fusd_dev
 */
wait for a driver to reply to a message
NOTE - we are already holding the lock on fusd_file_arg when this
function is called, but NOT the lock on the fusd_dev
wait for a driver to reply to a message NOTE - we are already holding the lock on fusd_file_arg when this function is called but NOT the lock on the fusd_dev
static int fusd_fops_call_wait(fusd_file_t *fusd_file_arg,
                               fusd_msg_t **fusd_msg_reply, struct fusd_transaction *transaction)
{
	fusd_dev_t *fusd_dev;
	fusd_file_t *fusd_file;
	int retval;
	GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev);
	if (fusd_msg_reply != NULL)
		*fusd_msg_reply = NULL;
	LOCK_FUSD_DEV(fusd_dev);
	while (transaction->msg_in == NULL) {
		DECLARE_WAITQUEUE(wait, current);
		RDEBUG(10, "pid %d blocking on transid %ld", current->pid, transaction->transid);
		current->state = TASK_INTERRUPTIBLE;
		add_wait_queue(&fusd_file->file_wait, &wait);
		UNLOCK_FUSD_DEV(fusd_dev);
		UNLOCK_FUSD_FILE(fusd_file);
		schedule();
		remove_wait_queue(&fusd_file->file_wait, &wait);
		current->state = TASK_RUNNING;
		if (signal_pending(current)) {
			RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS",
			       current->pid);
			LOCK_FUSD_FILE(fusd_file);
			return -ERESTARTSYS;
		}
		LOCK_FUSD_FILE(fusd_file);
		LOCK_FUSD_DEV(fusd_dev);
	}
	UNLOCK_FUSD_DEV(fusd_dev);
	if (transaction->msg_in->cmd != FUSD_FOPS_REPLY ||
	    transaction->msg_in->subcmd != transaction->subcmd ||
	    transaction->msg_in->parm.fops_msg.transid != transaction->transid ||
	    transaction->msg_in->parm.fops_msg.fusd_file != fusd_file) {
		RDEBUG(2, "fusd_fops_call: invalid reply!");
		goto invalid_reply;
	}
	fusd_file->file->f_flags = transaction->msg_in->parm.fops_msg.flags;
	fusd_file->private_data = transaction->msg_in->parm.fops_msg.private_info;
	retval = transaction->msg_in->parm.fops_msg.retval;
	if (fusd_msg_reply != NULL) {
		*fusd_msg_reply = transaction->msg_in;
		transaction->msg_in = NULL;
	} else {
		free_fusd_msg(&transaction->msg_in);
	}
	fusd_cleanup_transaction(fusd_file, transaction);
	return retval;
invalid_reply:
	fusd_cleanup_transaction(fusd_file, transaction);
	return -EPIPE;
invalid_dev:
invalid_file:
	RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!");
	return -EPIPE;
zombie_dev:
	RDEBUG(2, "fusd_fops_call: %s zombified while waiting for reply",
	       NAME(fusd_dev));
	return -EPIPE;
}
static int fusd_fops_call_wait ( fusd_file_t * fusd_file_arg , fusd_msg_t * * fusd_msg_reply , struct fusd_transaction * transaction ) { fusd_dev_t * fusd_dev ; fusd_file_t * fusd_file ; int retval ; GET_FUSD_FILE_AND_DEV ( fusd_file_arg , fusd_file , fusd_dev ) ; if ( fusd_msg_reply != NULL ) * fusd_msg_reply = NULL ; LOCK_FUSD_DEV ( fusd_dev ) ; while ( transaction -> msg_in == NULL ) { DECLARE_WAITQUEUE ( wait , current ) ; RDEBUG ( 10 , " " , current -> pid , transaction -> transid ) ; current -> state = TASK_INTERRUPTIBLE ; add_wait_queue ( & fusd_file -> file_wait , & wait ) ; UNLOCK_FUSD_DEV ( fusd_dev ) ; UNLOCK_FUSD_FILE ( fusd_file ) ; schedule ( ) ; remove_wait_queue ( & fusd_file -> file_wait , & wait ) ; current -> state = TASK_RUNNING ; if ( signal_pending ( current ) ) { RDEBUG ( 5 , " " , current -> pid ) ; LOCK_FUSD_FILE ( fusd_file ) ; return - ERESTARTSYS ; } LOCK_FUSD_FILE ( fusd_file ) ; LOCK_FUSD_DEV ( fusd_dev ) ; } UNLOCK_FUSD_DEV ( fusd_dev ) ; if ( transaction -> msg_in -> cmd != FUSD_FOPS_REPLY || transaction -> msg_in -> subcmd != transaction -> subcmd || transaction -> msg_in -> parm . fops_msg . transid != transaction -> transid || transaction -> msg_in -> parm . fops_msg . fusd_file != fusd_file ) { RDEBUG ( 2 , " " ) ; goto invalid_reply ; } fusd_file -> file -> f_flags = transaction -> msg_in -> parm . fops_msg . flags ; fusd_file -> private_data = transaction -> msg_in -> parm . fops_msg . private_info ; retval = transaction -> msg_in -> parm . fops_msg . retval ; if ( fusd_msg_reply != NULL ) { * fusd_msg_reply = transaction -> msg_in ; transaction -> msg_in = NULL ; } else { free_fusd_msg ( & transaction -> msg_in ) ; } fusd_cleanup_transaction ( fusd_file , transaction ) ; return retval ; invalid_reply : fusd_cleanup_transaction ( fusd_file , transaction ) ; return - EPIPE ; invalid_dev : invalid_file : RDEBUG ( 0 , " " ) ; return - EPIPE ; zombie_dev : RDEBUG ( 2 , " " , NAME ( fusd_dev ) ) ; return - EPIPE ; }
fusd_fops_call_wait: wait for a driver to reply to a message
 NOTE - we are already holding the lock on fusd_file_arg when this
 function is called, but NOT the lock on the fusd_dev
fusd_fops_call_wait : wait for a driver to reply to a message NOTE - we are already holding the lock on fusd_file_arg when this function is called but NOT the lock on the fusd_dev
/* I check this just in case, shouldn't be necessary. */ /* initialize first to tell callers there is no reply (yet) */ /*
	 * Now, lock the device, check for an incoming message, and sleep if
	 * there is not a message already waiting for us.  Note that we are
	 * unrolling the interruptible_sleep_on, as in the kernel's
	 * fs/pipe.c, to avoid race conditions between checking for the
	 * sleep condition and sleeping.
	 */ /*
		 * If we woke up due to a signal -- and not due to a reply message
		 * coming in -- then we are in some trouble.  The driver is already
		 * processing the request and might have changed some state that is
		 * hard to roll back.  So, we'll tell the process to restart the
		 * system call, and come back to this point when the system call is
		 * restarted.  We need to remember the PID to avoid confusion in
		 * case there is another process holding this file descriptor that
		 * is also trying to make a call.
		 */ /* re-lock the device, so we can do our msg_in check again */ /* ok - at this point we are awake due to a message received. */ /* copy metadata back from userspace */ /* note, changes to device_info are NO LONGER honored here */ /* if everything's okay, return the return value.  if caller is
	 * willing to take responsibility for freeing the message itself, we
	 * return the message too. */ /* NOW TRANSFERRING RESPONSIBILITY FOR FREEING THIS DATA TO THE CALLER */ /* free the message ourselves */ /* success */ /* bizarre errors go straight here */