#if	0			/* They are guaranteed not to work */
#ifndef	DFS_DOPEVECTORS
#define	DFS_DOPEVECTORS
#endif	DFS_DOPEVECTORS
#endif

/* rcsid[]="$Header: dfs.h,v 820.1 86/12/04 19:43:56 root Exp $" */
/* 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.				*
*									*
************************************************************************/

#ifndef	NRPC
#include "../DOT/rpc.h"
#endif

#if	NRPC > 0

#ifndef	VALID_RPC
#define	VALID_RPC		/* Enable the RPC facilities */
#endif

#ifndef	NDFS
#include "../DOT/dfs.h"
#endif

#if	NDFS > 0
#ifndef	VALID_DFS
#define	VALID_DFS		/* Enable the DFS facilities */
#endif

#endif	NDFS > 0

/*
 * Definitions for the Valid Logic Systems
 * Distributed File System.
 *
 *	Bakul Shah
 *
 * bvs 840313 -- original version (based on ../efs/efs.h)
 * jht 841115,16,26-29 -- complete conversion to use prpc.
 * jht 850123 -- add wcount, shlockc, exlockc to dfs_remote_t
 * jht 850213 -- add dfsPktHdr_t containing version/functionality info to pkts.
 * jht 850301 -- generalize descriptors into dope-vectors -- DFS_DOPE_VECTORS.
 * jht 850301 -- conversion to use new errno.h error-code mnemonics.
 * jht 850401 -- fill out the gathering of statistics.
 * jht 850414 -- differentiate between no remote struct and one not locked.
 * jht 850416 -- support for rwip() to do implicit ilock()/iunlock().
 * jht 850522 -- rpc, efs, dfs now autoconfigured pseudo-device subsystems.
 */

#ifndef	EPERM
#include "../h/errno.h"		/* Then "../h/errno.h" has not been scanned */
#endif	EPERM

/*
 * Various misc. constants
 */
#define	DFS_HOSTNAME_MAXLEN	20	/* Maximum length for a dfs hostname */
#define	DFS_ILLEGAL_INODE	((struct inode *)0xc0000000)   /* From namei */


#ifdef	DFS_DATA_DESCRIPTORS
#define	DFS_INODE_PADDING	0x10	/* For later growth of an inode */
#define	M_VFIELD(structure,descriptor) \
		m_field((caddr_t)	   (structure), \
			(caddr_t) ((u_long)(structure)  \
				+          (structure)->descriptor.d_offset))
#ifdef	DFS_DOPEVECTORS
/*
 * Compute the addr of the data associated
 * with the 'selector'-th descriptor
 * described by the descriptorDescriptor.
 *
 * Pictorially, we have the following situation:
 *
 */
#define	M_VVFIELD(structure,descriptorDescriptor,selector)	mindCramp!!!
#endif	DFS_DOPEVECTORS

/*
 * Descriptor for data structures which will
 * probably change in size over
 * the next couple of years.
 *
 * The main benefit is downward compatibility
 * for inode structures, which are highly
 * subject to change as we pursue object
 * oriented technology.
 */
typedef	struct	dataDescriptor_t {	/* Data descriptor	*/
	u_short	d_offset;		/* Offset of data	*/
	u_short	d_length;		/* Amount of data	*/
} desc_t;

#ifdef	DFS_DOPEVECTORS
typedef	struct	descDescriptor_t {	/* Descriptor descriptor	*/
	u_short	d_count;		/* # of descriptors described	*/
	desc_t	d_desc;			/* Location of descriptors	*/
} descDesc_t;
#endif	DFS_DOPEVECTORS
#endif	DFS_DATA_DESCRIPTORS


#ifdef	DFS_PACKETHDR
/*
 * DFS packet-header
 * to exchange DFS version number,
 * functionality supported,
 * and any other such information.
 */
 typedef	struct {
	u_char	majorVersNo;
	u_char	minorVersNo;
} dfs_vers_t;			/* Base-level is release 8.0 */

 typedef	struct	{
#ifdef	DFS_DOPEVECTORS
	descDesc_t	descDescrip;	/* Describe what will be described */

	/*
	 * Describe the two major categories
	 * of information: versionStuff and dataStuff.
	 */
	descDesc_t	versDescDesc;	/* Descriptor for version-desc's*/
	descDesc_t	dataDescDesc;	/* Descriptor for    data-desc's*/

	/*
	 * All version-information
	 * descriptors will go here...
	 */
	desc_t		versDesc;	/* Descriptor for version-info	*/
	desc_t		futureVersDesc;	/* Descriptor for future version*/

	/*
	 * All data-descriptorsss
	 * will go here...
	 */
	desc_t		dataDesc;	/* Descriptor for nominal data	*/
	desc_t		futureDataDesc;	/* Descriptor for future data	*/
#endif	DFS_DOPEVECTORS
	/*
	 * The version information, per se.
	 */
	dfs_vers_t	dfs_version;
	u_long		functions;   /* Function bit map: LSB ==> DFS_null() */
} dfsPktHdr_t;

 dfsPktHdr_t	myDfsPktHdr;	/* Set in dfs_init() */
#endif	DFS_PACKETHDR

/*
 * Remote structure for DFS.
 * These data structures are only present
 * for a file on the Server side.
 * They are not accessible from the Client side.
 */
typedef struct dfs_remote {
	struct dfs_remote *nexthash;	/* Hash link			*/
	struct dfs_remote *next;	/* Another entry for same inode */
	u_long		   flags;	/* Flags for this entry		*/
	struct inode *	   ip;		/* Inode referred to		*/
	node_t	 	   node;	/* from this node		*/
	short		   count;	/* # of remote references	*/
	short		   wcount;	/* # of remote write refs	*/
	short		   shlockc;	/* # of remote shared locks	*/
	short		   exlockc;	/* # of remote exclusive locks	*/
	long		   locktime;	/* Time when we get the lock	*/
} dfs_remote_t;

/*
 * dfs_remote->flags
 * The flags indicate how the inode
 * is being used by a remote node.
 */
#define	DFS_RMT_LOCKED	0x1		/* Inode is locked		*/
#define	DFS_RMT_UPD	0x2		/* File has been modified	*/
#define	DFS_RMT_ACC	0x4		/* Inode access time to be updated */
#define	DFS_RMT_MOUNT	0x8		/* Inode is mounted on		*/
#define	DFS_RMT_WANT	0x10		/* Some process waiting on lock	*/
#define	DFS_RMT_TEXT	0x20		/* Inode is pure text prototype	*/
#define	DFS_RMT_CHG	0x40		/* Inode has been changed	*/
#define	DFS_RMT_SHLOCK	0x80		/* File has shared lock		*/
#define	DFS_RMT_EXLOCK	0x100		/* File has exclusive lock	*/
#define	DFS_RMT_LWAIT	0x200		/* Someone waiting on file lock	*/
#define DFS_RMT_OPENWRITE 0x400		/* Inode opened for write	*/

/*
 * These flags reflect the state of remote inode.
 * They are copied to the agent when the remote inode is locked,
 * and copied back when the remote inode is updated.
 * [Note that ILOCK and IWANT flags are used
 * for locking the local inode]
 */
#define DFS_INODE_FLAGS(f)  ((f) & (ICHG|IUPD|IACC|ISHLOCK|IEXLOCK|IOPENWRITE))

/*
 * If a remotely locked inode is not used within
 * this time and somebody else wants to lock
 * the inode, the lock will be broken.
 */
#define	DFS_INODE_LOCK_TIME 	60	/* Seconds til inode lock-breakage    */
					/* Risk 'panic:iput' with this one!   */

/*
 * DFS degugging macros
 */
#ifdef	DEBUG
#define	DFS_DEBUG(lvl,printfArgs)	if(dfs_debug>=(lvl))printf printfArgs
#else	DEBUG
#define	DFS_DEBUG(lvl,printfArgs)
#endif	DEBUG

/*
 * Statistics
 */
typedef struct {
	long	current;	/* Current count for this statistic */
	long	total;		/* Total counts		*/
	long	maximum;	/* Maximum at any time	*/
} dfs_count_t;

typedef struct {
	long	server;		/* Number of these calls serviced */
	long	client;		/* Number of these calls requested remotely */
	long	clientAbort;	/* Number of client calls that were aborted */
	long	serverAbort;	/* Number of server calls that were aborted */
} dfs_call_t;

/*
 * Statistics buckets:
 *
 * 1) 'local' is with respect
 * to the real inodes ==> server side;
 *
 * 2) 'remote' is with respect
 * to the agent inodes ==> client side;
 */
typedef struct dfs_stats {
	dfs_count_t	localFiles;	/* Local  files open	*/
	dfs_count_t	remoteFiles;	/* Remote files open	*/

/* ServerSide locks and counts:	*/
	dfs_count_t	writeCount;	/* Aggregate opens-for-write	*/
	dfs_count_t	sharedLocks;	/* Aggregate shared-locks	*/
	dfs_count_t	exclusiveLocks;	/* Aggregate exclusive-locks	*/
	long		brokenLocks;	/* Locks broken due to timeout	*/

/* Overrun of DFS data structures */
	long		localFull;	/* Local  file table full	*/
	long		remoteFull;	/* Remote file table full	*/

/* Drop-dead counts */
	long		clientCrashes;	/* Remote client nodes crashed	*/
	long		serverCrashes;	/* Remote server nodes crashed	*/
#define	remoteCrashes	serverCrashes
	long		localDropped;	/* Local  files dropped due to a crash*/
	long		remoteDropped;	/* Remote files dropped due to a crash*/

/* UP/DOWN of DFS functionality */
	long		shutdowns;	/* Shutdown	of DFS interface*/
	long		disable;	/* Disablement	of DFS interface*/
	long		enable;		/* Enablement	of DFS interface*/

/* Internal data transfer operations */
	long		mbuftouio;	/* mbuf to uio   transfer	*/
	long		uiocopy;	/* uio  to uio   transfer	*/
	long		mtombuf;	/* RAM  to mbuf  transfer	*/
	long		mbuftom;	/* mbuf to RAM   transfer	*/
	long		mbuftoinode;	/* mbuf to inode transfer	*/

/* External transfer done for higher layer (client) */
	dfs_call_t	readBytes;	/* Bytes  read	  (rwip)	*/
	dfs_call_t	writeBytes;	/* Bytes  written (rwip)	*/

/* Exception checking/handling */
	dfs_call_t	validContext;	/* Context validation checks	*/
	dfs_call_t	exception;	/* exception invocations	*/

/* Test operations */
	dfs_call_t	null;		/* null   	calls	*/
	dfs_call_t	echo;		/* echo   	calls	*/

/* Basic inode operations */
	dfs_call_t	ilock;		/* ilock  	calls & aborts	*/
	dfs_call_t	iunlock;	/* iunlock  	calls	*/
	dfs_call_t	irele;		/* irele  	calls	*/
	dfs_call_t	iupdat;		/* iupdat  	calls	*/

/* File operations */
	dfs_call_t	access;		/* access  	calls	*/
	dfs_call_t	rwip;		/* rwip  	calls	*/
	dfs_call_t	  reads;	/* read  	calls (within rwip) */
	dfs_call_t	  writes;	/* write  	calls (within rwip) */
	dfs_call_t	ioctl;		/* ioctl  	calls	*/
	dfs_call_t	itrunc;		/* itrunc  	calls	*/
	dfs_call_t	syncip;		/* syncip  	calls	*/
	dfs_call_t	openi;		/* openi  	calls	*/
	dfs_call_t	ilink;		/* ilink  	calls	*/

/* namei operations */
	dfs_call_t	namei;		/* namei  	calls & aborts	*/
	dfs_call_t	direnter;	/* direnter  	calls	*/
	dfs_call_t	dirremove;	/* dirremove  	calls	*/
	dfs_call_t	maknode;	/* maknode  	calls & aborts	*/
	dfs_call_t	mkdir;		/* mkdir  	calls	*/
	dfs_call_t	rmdir;		/* rmdir  	calls	*/
} dfs_stats_t;

/*
 * SIZE constants
 */
#define DFS_DATASIZE	1024
#define DFS_PATHSIZE	512

/*
 * Test operations
 */
#define DFS_null	0
#define DFS_echo	1
#ifdef	DFS_PACKETHDR
#define DFS_testOps	((1<<DFS_null)\
			|(1<<DFS_echo))
#endif	DFS_PACKETHDR

/*
 * Basic inode operations
 */
#define DFS_ilock	2
#define DFS_iunlock	3
#define DFS_irele	4
#define DFS_iupdat	5
#ifdef	DFS_PACKETHDR
#define DFS_inodeOps	((1<<DFS_ilock)	 \
			|(1<<DFS_iunlock)\
			|(1<<DFS_irele)	 \
			|(1<<DFS_iupdat))
#endif	DFS_PACKETHDR

/*
 * File operations
 */
#define DFS_access	6
#define DFS_rwip	7
#ifdef	DFS_NEW_RWIP
#define DFS_lokRwip	22	/* serverSide to do ilock()/iunlock() */
#endif	DFS_NEW_RWIP
#define DFS_ioctl	8
#define DFS_itrunc	9
#define DFS_syncip	10
#define DFS_openi	11
#define DFS_ilink	12
#ifdef	DFS_PACKETHDR
#ifndef	DFS_NEW_RWIP

#define DFS_fileOps	((1<<DFS_access)\
			|(1<<DFS_rwip)	\
			|(1<<DFS_ioctl)	\
			|(1<<DFS_itrunc)\
			|(1<<DFS_syncip)\
			|(1<<DFS_openi)	\
			|(1<<DFS_ilink))
#else	DFS_NEW_RWIP

#define DFS_fileOps	((1<<DFS_access)\
			|(1<<DFS_rwip)	\
			|(1<<DFS_lokRwip)	/* New functionality */ \
			|(1<<DFS_ioctl)	\
			|(1<<DFS_itrunc)\
			|(1<<DFS_syncip)\
			|(1<<DFS_openi)	\
			|(1<<DFS_ilink))
#endif	DFS_NEW_RWIP
#endif	DFS_PACKETHDR

/*
 * namei() operations
 */
#define DFS_namei	16
#define DFS_direnter	17
#define DFS_dirremove	18
#define DFS_maknode	19
#define DFS_mkdir	20
#define DFS_rmdir	21
#ifdef	DFS_PACKETHDR
#define DFS_nameiOps	((1<<DFS_namei)		\
			|(1<<DFS_direnter)	\
			|(1<<DFS_dirremove)	\
			|(1<<DFS_maknode)	\
			|(1<<DFS_mkdir)		\
			|(1<<DFS_rmdir))
#endif	DFS_PACKETHDR

#ifndef	DFS_NEW_RWIP
#define DFS_OP_COUNT	22
#else	DFS_NEW_RWIP
#define DFS_OP_COUNT	23
#endif	DFS_NEW_RWIP

#ifdef	DFS_PACKETHDR
#define DFS_FUNCTIONS	(u_long)	\
			(DFS_testOps	\
			|DFS_inodeOps	\
			|DFS_fileOps	\
			|DFS_nameiOps)
#endif	DFS_PACKETHDR

/*
 * Macros
 */

/*
 * Macros for creating data for statistical analysis:
 * Current, maximum, total.
 */
#define dfs_incStat(stat) {\
	++dfs_stats.stat.total; \
	if (++dfs_stats.stat.current > dfs_stats.stat.maximum) \
		dfs_stats.stat.maximum = dfs_stats.stat.current;}

#define dfs_decStat(stat)	--dfs_stats.stat.current
/*
 * Macros referencing dfs_call_t:
 */
#define dfs_incServer(stat)	++dfs_stats.stat.server
#define dfs_incClient(stat)	++dfs_stats.stat.client
#define dfs_incClientAbort(stat)	++dfs_stats.stat.serverAbort
#define dfs_incServerAbort(stat)	++dfs_stats.stat.serverAbort
/*
 * Macro for tallying
 * singleton bean counters.
 */
#define dfs_incTotal(stat)	++dfs_stats.stat

/*
 * Macros for allocating call packets
 */
#ifndef	DFS_PACKETHDR
#define DFSC_PACKET(type)						\
	(dfsc_/**/type/**/_t *)						\
		rpc_allocParams( sizeof (dfsc_/**/type/**/_t))

#define DFSC_VPACKET(type, extra)					\
	(dfsc_/**/type/**/_t *)						\
		rpc_allocParams( sizeof (dfsc_/**/type/**/_t) + (extra))

#else	DFS_PACKETHDR

/*
 * Allocate call packets
 * AND initialize the dfsPktHdr
 * at the front of the call-pkt.
 *
 * 'call' is the presumed ptr
 * to the call packet.
 */
#define DFSC_PACKET(type)						    \
	(dfsc_/**/type/**/_t *)						    \
		rpc_allocParams( sizeof (dfsc_/**/type/**/_t))		    \
		;{register i; for (i=0; i<(sizeof(dfsPktHdr_t)>>1); i++)    \
			*((u_short *)call+i) = *((u_short *)&myDfsPktHdr+i);\
		 } if (1);else;

#define DFSC_VPACKET(type, extra)					    \
	(dfsc_/**/type/**/_t *)						    \
		rpc_allocParams( sizeof (dfsc_/**/type/**/_t) + (extra))    \
		;{register i; for (i=0; i<(sizeof(dfsPktHdr_t)>>1); i++)    \
			*((u_short *)call+i) = *((u_short *)&myDfsPktHdr+i);\
		 } if (1);else;
#endif	DFS_PACKETHDR



/*
 * Macros for allocating return-pkts
 */
#ifndef	DFS_PACKETHDR
#define DFSR_PACKET(type)		\
	(dfsr_/**/type/**/_t *)		\
		rpc_allocResults( sizeof (dfsr_/**/type/**/_t))

#define DFSR_VPACKET(type, extra)	\
	(dfsr_/**/type/**/_t *)		\
		rpc_allocResults( sizeof (dfsr_/**/type/**/_t) + (extra))
#else	DFS_PACKETHDR
/*
 * Allocate result packets
 * AND initialize the dfsPktHdr
 * at the front of the result-pkt.
 *
 * 'result' is the presumed ptr
 * to the result packet.
 */
#define DFSR_PACKET(type)		\
	(dfsr_/**/type/**/_t *)		\
		rpc_allocResults( sizeof (dfsr_/**/type/**/_t))\
		;{register i; for (i=0; i<(sizeof(dfsPktHdr_t)>>1); i++)    \
			*((u_short *)result+i) = *((u_short *)&myDfsPktHdr+i);\
		 } if (1);else;

#define DFSR_VPACKET(type, extra)	\
	(dfsr_/**/type/**/_t *)		\
		rpc_allocResults( sizeof (dfsr_/**/type/**/_t) + (extra))\
		;{register i; for (i=0; i<(sizeof(dfsPktHdr_t)>>1); i++)    \
			*((u_short *)result+i) = *((u_short *)&myDfsPktHdr+i);\
		 } if (1);else;
#endif	DFS_PACKETHDR

/*
 * Macros for de-allocating packets
 */
#define DFS_FREE_PARAMS(params)		rpc_freeParams(params)   /* Call   pkt*/
#define DFS_FREE_RESULTS(results)	rpc_freeResults(results) /* Return pkt*/

/*
 * Macros for function invocation/return
 */
#define DFS_CALL(conn,	type, params)	\
	(dfsr_/**/type/**/_t *)		\
	prpc_call(&dfsClientClass,conn,RPC_CLASS_DFS,DFS_/**/type,params)

#define DFS_RETURN(x)	return ((x))

/*
 * Macro for node/host lookup.
 */
#define DFS_NODE(clientConnp)	(&(clientConnp)->node)/* ONLY on SERVER side! */

/*
 * Macro to get to the variable sized data
 * just beyond the packet header
 */
#define DFS_DATA(p)	((caddr_t)&(p)[1])

/*
 * Macros for controlling remote super user access
 * The second arg. call will be used in looking up
 * a list of legal remote super users.
 */
#define DFS_UID(uid, clientConn)	((uid)?(uid):dfs_uid(DFS_NODE(clientConn)))
#define DFS_GID(gid, clientConn)	((gid)?(gid):dfs_gid(DFS_NODE(clientConn)))

#define DFS_SETJMP() \
	{ \
		label_t dfsoldqsave; \
		dfsoldqsave = u.u_qsave; \
		if (setjmp(&u.u_qsave)) \
			result->interrupted = 1; \
		else { \
			u.u_eosys = JUSTRETURN;

			/*
			 * The code specific to the function
			 * would go in here, between the SETJMP
			 * and the UNSETJMP.
			 */

#define DFS_UNSETJMP() \
			result->interrupted = 0; \
		} \
		result->junk = 0; \
		result->error = u.u_error; \
		result->eosys = u.u_eosys; \
		u.u_qsave = dfsoldqsave; \
	}

/*
 * Conversion macros
 */
#define GROUPSIZE		(sizeof(u.u_groups))
#define denttombuf(mdent,  dent)	mtombuf(mdent,	dent,	DIRSIZ(dent))
#define groupstombuf(mgrp, grp)		mtombuf(mgrp,	grp,	GROUPSIZE)
#define inodetombuf(mip,   ip)		mtombuf(mip,	ip,	sizeof(*ip))

#define mbuftodent(dentDst, mdentSrc)	\
	if (1) {\
		register struct direct * dp = (struct direct *)(mdentSrc); \
		(dentDst)->d_namlen = *(u_short *)m_field(dp, &dp->d_namlen);\
		mbuftom((dentDst), dp, DIRSIZ(dentDst)); \
	} else ;	/* ...cause '{ ... };' gives syntax error! */

#define mbuftogroups(grp, mgrp)	mbuftom(grp, mgrp, GROUPSIZE)

/*
 * u.u_error values relevant to DFS:
 */
#define	DFS_ENOHOST	EHOSTUNREACH	/* No such host in host table	      */
#define	DFS_EBADIOCTL	EBADIOCTL	/* Invalid ioctl() request	      */
#define	DFS_ECRASHED	ESERVERCRASHED	/* Server-side has crashed	      */
#define	DFS_EREMOTESOCK	EREMOTESOCK	/* May not access remote socket	      */
#define	DFS_EREMOTEBDEV	EREMOTEBDEV	/* May not access remote block device */
#define	DFS_EINVAL	EBADIPTR	/* Invalid inode ptr specified	      */
#define	DFS_EBADRMTDESC	EBADRMTDESC	/* No DFS rmt descriptor	      */
#define	DFS_EXHOST	EXHOST		/* Attempt to link  across 2 hosts    */
#define	DFS_ENOTENABLED	EDFSNOTENABLED	/* DFS is not enabled		      */
#define	DFS_ERMTFULL	EDFSRMTFULL	/* No more inode descriptors @ remote */
#define	DFS_EINCOMPAT	EDFSINCOMPATVERS/* incompatibile DFS version/function */
#define	DFS_EFAULT	EFAULT		/* Bad address detected		      */
#define	DFS_EMULTIHOSTREF EMULTIHOSTREF	/* Multiple host-reference in pathname*/

#define	DFS_ERMTNOTLOCKED EDFSRMTNOTLOCKED /* DFS rmt descriptor not locked   */
#define	DFS_EDFSABORT EDFSABORT		/* DFS function instructed to abort   */

#ifdef KERNEL

extern	dfs_remote_t *		dfs_remotes[];
extern	dfs_remote_t * *	dfs_remotesNSLOTS;
extern	rpc_clientClass_t	dfsClientClass;

extern	int			dfs_enabled;	/* Enable/disable	*/
extern	int			dfs_debug;	/* Enable/disable	*/
extern	int			dfs_lock_time;	/* Before breaking lock	*/
extern	connection_t		myConn;		/* Conn for our node	*/

dev_t	    dfs_dev;		/* Character device number of the DFS driver */
dfs_stats_t dfs_stats;		/* Statistics for the DFS */


extern struct connection *conn_addr();
extern mbufchar();
extern struct inode *	dfs_mkagent();
extern struct inode *	maknode();
extern dfs_remote_t *	dfs_rmt_find();
extern dfs_remote_t *	dfs_rmt_remove();
extern struct inode *	dfs_root();
extern struct inode *	dfsClient_namei();
#endif KERNEL

#else	NRPC > 0

#ifdef	VALID_RPC
#undef	VALID_RPC		/* Disable the RPC facilities */
#endif

#ifdef	VALID_DFS
#undef	VALID_DFS		/* Disable the DFS facilities */
#endif

#endif	NRPC > 0
