#ifndef _ADOS_ANODE_H_
#define _ADOS_ANODE_H_

/***
Copyright (c) 1991, 1992 by Frank J. Edwards
See the file COPYRIGHT in this distribution for copyright details.
***/

#ident "$Id: ados_anode.h,v 1.13 1992/11/20 04:03:11 root Rel root $"

#include "sys/vnode.h"	/* (struct anode) contains struct, not pointer */
#include "sys/debug.h"	/* For ASSERT */

#ifndef _ADOS_DEFS_H
# include "ados_defs.h"
#endif

struct llchain {
    struct llchain *ll_forw, *ll_back;
    int		 ll_next;	/* next available slot in ll_addr[] (0..71) */
    LONG	 ll_keyblk;	/* Blk of hdr/ext; # blk's in ll_addr if dir */
    LONG	 ll_exten;	/* Blk of next extension */
    LONG	 ll_addr[72];
};

struct anode {
    struct anode *a_forw;	/* free/used anode chain */
    struct anode *a_back;
    struct llchain a_ll;
    vnode_t      a_vnode;	/* a_vnode.v_data == &a_forw */
    LONG	 a_keyblk;	/* NOT THE SAME as in (struct llchain) */
    int		 a_idx;		/* Current hdr/ext block (from a_addr) */
    struct fbuf	*a_map;		/* Mapping of current hdr/ext block */
    char	 a_name[32];	/* Name of anode in filesystem */

    size_t	 a_blocks;	/* Number of blocks.  Used for directories */
    off_t	 a_size;	/* Bytesize of the file (min of blks * 512) */
    mode_t	 a_mode;
    uid_t	 a_uid;		/* file /etc/ados/uid contains uid xlates */
    gid_t	 a_gid;		/* file /etc/ados/gid contains gid xlates */
    int		 a_nlink;
    timestruc_t	 a_mtime;	/* modification timestamp */

    int		 a_owner;
    int		 a_nilocks;
    ulong	 a_vcode;
    u_short	 a_flag;
};

typedef struct anode anode_t;
/* typedef struct vnode vnode_t; */

/*
 * anode-to-vnode conversion.
 */
#define	ATOV(ap)	((vnode_t *)&(ap)->a_vnode)
#define VTOA(vp)	((anode_t *)(vp)->v_data)

/* Flags */

#define	ILOCKED		0x0001	/* inode is locked */
#define	IUPD		0x0002	/* file has been modified */
#define	IACC		0x0004	/* inode access time to be updated */
#define	IWANT		0x0010	/* some process waiting on lock */
#define	ICHG		0x0040	/* inode has been changed */
#define	ISYN		0x0080	/* do synchronous write for iupdat */
#define	IMOD		0x0100	/* inode times have been modified */
#define	INOACC		0x0200	/* no access time update in getpage */
#define	ISYNC		0x0400	/* do all block allocation synchronously */
#define	IMODTIME	0x0800	/* mod time already set */
#define	IRWLOCKED	0x1000	/* inode is rwlocked */

/*
 * Lock and unlock inodes.
 *
 * XXX -- Uses process context.  Rewrite to remove this.
 *
 *	IRWLOCK(ap)	lock anode for data access
 *	IRWUNLOCK(ap)	unlock anode for data access
 *
 *	ILOCK(ap)	lock anode for anode access
 *	IUNLOCK(ap)	unlock anode for anode access
 */

#define IN_MACRO(a,y)	DBG("Macro " # a "; %x @ %x", (y)->a_flag, (y), 0)

#define	IRWLOCK(ap) { \
	IN_MACRO(IRWLOCK, ap); \
	while ((ap)->a_flag & IRWLOCKED) { \
		(ap)->a_flag |= IWANT; \
		(void) sleep((caddr_t)(ap), PINOD); \
	} \
	(ap)->a_flag |= IRWLOCKED; \
	if ((ap)->a_vnode.v_flag & VISSWAP) { \
		curproc->p_swlocks++; \
		curproc->p_flag |= SSWLOCKS; \
	} \
}

#define	IRWUNLOCK(ap) { \
	ASSERT((ap)->a_flag & IRWLOCKED); \
	IN_MACRO(IRWUNLOCK, ap); \
	if ((ap)->a_vnode.v_flag & VISSWAP) { \
		if (--curproc->p_swlocks == 0) \
			curproc->p_flag &= ~SSWLOCKS; \
	} \
	(ap)->a_flag &= ~IRWLOCKED; \
	if ((ap)->a_flag & IWANT) { \
		(ap)->a_flag &= ~IWANT; \
		wakeprocs((caddr_t)(ap), PRMPT); \
	} \
}

#define	ILOCK(ap) { \
	IN_MACRO(ILOCK, ap); \
	while (((ap)->a_flag & ILOCKED) && (ap)->a_owner != curproc->p_slot) { \
		(ap)->a_flag |= IWANT; \
		(void) sleep((caddr_t)(ap), PINOD); \
	} \
	(ap)->a_owner = curproc->p_slot; \
	(ap)->a_nilocks++; \
	(ap)->a_flag |= ILOCKED; \
	if ((ap)->a_vnode.v_flag & VISSWAP) { \
		curproc->p_swlocks++; \
		curproc->p_flag |= SSWLOCKS; \
	} \
}

#define	IUNLOCK(ap) { \
	ASSERT((ap)->a_flag & ILOCKED); \
	IN_MACRO(IUNLOCK, ap); \
	--(ap)->a_nilocks; \
	ASSERT((ap)->a_nilocks >= 0); \
	if ((ap)->a_vnode.v_flag & VISSWAP) { \
		if (--curproc->p_swlocks == 0) \
			curproc->p_flag &= ~SSWLOCKS; \
	} \
	if ((ap)->a_nilocks == 0) { \
		(ap)->a_flag &= ~ILOCKED; \
		if ((ap)->a_flag & IWANT) { \
			(ap)->a_flag &= ~IWANT; \
			wakeprocs((caddr_t)(ap), PRMPT); \
		} \
	} \
}

#endif /* _ADOS_ANODE_H_ */
