/* adosfs_anode.h 930818 Niklas Hallqvist <niklas@appli.se> */

/* Adapted from Frank J. Edwards' Amix AmigaDOS FS implementation.  */

#ifndef _ADOSFS_ADOSFS_ANODE_H_
#define _ADOSFS_ADOSFS_ANODE_H_

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

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

struct anode {
  struct anode *a_forw;		/* free/used anode chain */
  struct anode *a_back;
  struct llchain *a_ll;
  struct vnode *a_vnode;	/* &a_vnode->v_data == &a_forw */
  ados_u_long a_keyblk;		/* NOT THE SAME as in (struct llchain) */
  dev_t a_dev;
  int a_idx;			/* Current hdr/ext block (in a_ll->ll_addr) */
  struct fbuf *a_map;		/* Mapping of current hdr/ext block */
  char a_name[NAMESIZE];	/* 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;
  struct timeval a_mtime;	/* modification timestamp */
  int a_owner;
  int a_nilocks;
  u_long a_vcode;
  u_short a_flag;
  ados_u_long a_parent;
  long a_spare0;
  long a_spare1;
};

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

/* Flags */

#define	ALOCKED		0x0001	/* inode is locked */
#if 0
#define	AUPD		0x0002	/* file has been modified */
#define	AACC		0x0004	/* inode access time to be updated */
#endif
#define	AWANT		0x0010	/* some process waiting on lock */
#if 0
#define	ACHG		0x0040	/* inode has been changed */
#define	ASYN		0x0080	/* do synchronous write for iupdat */
#define	AMOD		0x0100	/* inode times have been modified */
#define	ANOACC		0x0200	/* no access time update in getpage */
#define	ASYNC		0x0400	/* do all block allocation synchronously */
#define	AMODTIME	0x0800	/* mod time already set */
#define	ARWLOCKED	0x1000	/* inode is rwlocked */
#endif

#define ALOCK(ap) alock (ap)
#define AUNLOCK(ap) aunlock (ap)

#if 0
/*
 * 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

#endif /* _ADOSFS_ADOSFS_ANODE_H_ */
