static char rcsid[] = "$Header: dfs_syscalls.c,v 820.1 86/12/04 19:45:02 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * DFS routines for ufs_syscalls.c
 *
 *	Bakul Shah
 *
 * bvs 840313 -- original version
 * jht 841115,16,26-29 -- complete conversion to use prpc.
 * jht 850213 -- add dfsPktHdr_t containing version/functionality info to pkts.
 * jht 850401 -- fill out the gathering of statistics.
 * jht 850414 -- differentiate between no remote struct and one not locked.
 * jht 850414 -- complete DFS_LOCK_FIX for mknode(): clear i_rmt_lock.
 */

#include "../h/param.h"
#include "../h/ioctl.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"

#include "../vnet/vnet.h"
#include "../conn/conn.h"
#include "../rpc/rpc.h"
#include "../dfs/dfs.h"

#include "../h/inode.h"
#include "../h/socket.h"
#include "../h/kernel.h"
#include "../net/if.h"
#include "../h/mbuf.h"


typedef struct dfsc_maknode {		/* Pkt from client --> server	*/
#ifdef	DFS_PACKETHDR
	dfsPktHdr_t	dfsPktHdr;	/* Info about DFS versions, etc	*/
#endif	DFS_PACKETHDR
	caddr_t		parent;		/* Parent directory		*/
	long		offset;		/* Create at this offset	*/
	long		count;		/* Size of the hole		*/
	short		mode;		/* File mode			*/
	short		cmask;		/* Create mask			*/
	short		uid;		/* User id			*/
	/* Directory entry  follows the header */
} dfsc_maknode_t;

typedef struct dfsr_maknode {		/* Pkt from client <-- server	*/
#ifdef	DFS_PACKETHDR
	dfsPktHdr_t	dfsPktHdr;	/* Info about DFS versions, etc	*/
#endif	DFS_PACKETHDR
	int		error;		/* Error number or 0 on success	*/
	caddr_t		ip;		/* Created inode		*/
	struct inode	inode;		/* Contents of the inode	*/
} dfsr_maknode_t;

/*
 * Remote maknode.
 * Sockets can not be created on a remote machine.
 * Pack mode, uid, cmask, offset, count, parent dir ip, dent
 * in a call packet and make a remote call.
 * The result contans the inode ptr and contents of inode.
 */
struct inode *
dfsClient_maknode(mode)
{
	register dfsc_maknode_t	* call;
	register dfsr_maknode_t	* result;
	register struct inode	* ip = NULL;
	register struct inode	* dp = u.u_pdir;	/* Parent inode */
	
	dfs_incClient(maknode);
	/*
	 * Sockets or block devices
	 * may not be created on a remote node
	 */
	if ((mode & IFMT) == IFSOCK) {
		u.u_error = DFS_EREMOTESOCK;
		goto ret;
	}
	if ((mode & IFMT) == IFBLK) {
		u.u_error = DFS_EREMOTEBDEV;
		goto ret;
	}
	/*
	 * Sanity checks
	 */
	if (!dfsClient_validContext(dp, "maknode"))	/* NOTE we pass dp! */
		goto ret;
	if (!dp->i_rmt_ip) {
		u.u_error = DFS_ECRASHED;
		goto ret;
	}
	/*
	 * Now the real processing
	 */
	call = DFSC_VPACKET(maknode, DIRSIZ(&u.u_dent));
	if (!call)
		goto ret;
	call->mode   = mode;
	call->parent = dp->i_rmt_ip;	/* Parent inode @ remote host */
	call->uid    = u.u_uid;
	call->cmask  = u.u_cmask;
	call->offset = u.u_offset;
	call->count  = u.u_count;
	denttombuf(m_field(call, DFS_DATA(call)), &u.u_dent);
	result       = DFS_CALL(dp->i_host,maknode,call);
	if (!result)
		goto ret;
	u.u_error = result->error;
	/*
	 * We get back a locked inode
	 * for the (new) child.
	 */
	if (result->ip)
		ip = dfs_mkagent(u.u_pdir->i_host, &result->inode, result->ip);
	DFS_FREE_RESULTS(result);
	/*
	 * Release local resources associated
	 * with the parent inode.
	 * The server-side has already unlocked the parent.
	 */
	IUNLOCK(dp);
	dfs_irele(dp);
	return ip;
ret:
	iput(dp);
	return ip;
}

/*
 * Remote maknode.
 *
 * Receive a pointer to a locked parent.
 * Return a locked inode for the new child.
 * Parent inode is unlocked upon exit.
 */
dfsr_maknode_t *
dfsServer_maknode(clientConn, clientId, operation, call)
	connection_t		* clientConn;	/* Host we are serving	*/
	u_long			  clientId;	/* Specific client@host	*/
	u_short			  operation;	/* Redundant: what to do*/
	register dfsc_maknode_t	* call;		/* Call pkt -- params	*/
{
	register dfsr_maknode_t * result;
	register struct inode	* child_ip;
	register dfs_remote_t	* rp;		/* ...for the parent */

	dfs_incServer(maknode);
	result = DFSR_PACKET(maknode);
	if (!result) {
		DFS_FREE_PARAMS(call);
		return NULL;		/* Say "no result pkt" */
	}
	rp = dfs_rmt_find(DFS_NODE(clientConn), call->parent);
	/*
	 * The parent inode must have be locked
	 * before we can add a new <inum, name> pair.
	 */
	if (!rp || !(rp->flags & DFS_RMT_LOCKED)) {
		result->error = !rp ? DFS_EBADRMTDESC : DFS_ERMTNOTLOCKED;
		DFS_FREE_PARAMS(call);
		DFS_RETURN(result);
	}
	rp->locktime = UPTIME();

	u.u_pdir      = (struct inode *) call->parent;
	u.u_offset    = call->offset;
	u.u_count     = call->count;
	u.u_uid       = DFS_UID(call->uid, clientConn);
	u.u_cmask     = call->cmask;
	mbuftodent(&u.u_dent, m_field(call, DFS_DATA(call)));
	/*
	 * Make a new (locked) inode.
	 */
	child_ip      = maknode(call->mode);	/* Inode for child of parent */
	if (!u.u_error) {
		/*
		 * Copy the new child inode contents into result-pkt
		 * and add a new remote entry for the child inode.
		 */
		result->ip =				(caddr_t) child_ip;
		inodetombuf(m_field(result, &result->inode),	  child_ip);
		dfs_rmt_add(DFS_NODE(clientConn),		  child_ip);
	}
	/*
	 * The client-side will unlock the parent inode.
	 * Cleanup the/our remote resources
	 * associated with the parent.
	 */
	rp->flags &= ~DFS_RMT_LOCKED;
	dfs_rmt_remove(DFS_NODE(clientConn), call->parent);
#ifdef	DFS_LOCK_FIX
	((struct inode *)(call->parent))->i_rmt_lock = NULL;
#endif	DFS_LOCK_FIX

	/*
	 * We are complete at this point.
	 */
	result->error = u.u_error;
	if (u.u_procp->p_rpcflags & RPCFLAG_ABORTED) {
		/*
		 * Release the resources
		 * associated with the child.
		 * BUG: Should we change result->error
		 * BUG: to reflect RPCFLAG_ABORTED.
		 */
		dfsServer_maknodeAbort(clientConn, child_ip);
	}
	DFS_FREE_PARAMS(call);
	DFS_RETURN(result);
}
/*
 * Release the resources
 * associated with the child portion
 * of an ABORT-ed remote maknode().
 */
dfsServer_maknodeAbort(clientConn, child_ip)
	connection_t		* clientConn;	/* Host we are serving	*/
	register struct inode	* child_ip;
{
	register dfs_remote_t	* rp;

	dfs_incServerAbort(maknode);
	if (rp = dfs_rmt_find(DFS_NODE(clientConn), child_ip)) {
		rp->flags &= ~DFS_RMT_LOCKED;
		dfs_rmt_remove(DFS_NODE(clientConn), child_ip);
#ifdef	DFS_LOCK_FIX
		child_ip->i_rmt_lock = NULL;
#endif	DFS_LOCK_FIX
		if (child_ip->i_flag & ILOCKED)
			iput(child_ip);
		else
			irele(child_ip);
	}
}
