/* @(#)src/common/kernel/base/vx_inode.h	3.90.19.6 10/04/99 20:27:37 -  */
/* #ident "@(#)vxfs:src/common/kernel/base/vx_inode.h	3.90.19.6" */

/*
 * Copyright (c) 1998 VERITAS Software Corporation.  ALL RIGHTS RESERVED.
 * UNPUBLISHED -- RIGHTS RESERVED UNDER THE COPYRIGHT
 * LAWS OF THE UNITED STATES.  USE OF A COPYRIGHT NOTICE
 * IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
 * OR DISCLOSURE.
 *
 * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND
 * TRADE SECRETS OF VERITAS SOFTWARE.  USE, DISCLOSURE,
 * OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
 * EXPRESS WRITTEN PERMISSION OF VERITAS SOFTWARE.
 *
 * 		RESTRICTED RIGHTS LEGEND
 * USE, DUPLICATION, OR DISCLOSURE BY THE GOVERNMENT IS
 * SUBJECT TO RESTRICTIONS AS SET FORTH IN SUBPARAGRAPH
 * (C) (1) (ii) OF THE RIGHTS IN TECHNICAL DATA AND
 * COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013.
 * 		VERITAS SOFTWARE
 * 1600 PLYMOUTH STREET, MOUNTAIN VIEW, CA 94043
 */

#ifndef	_FS_VXFS_VX_INODE_H
#define	_FS_VXFS_VX_INODE_H

/*
 * The head of the inode cache lists.
 *
 * The offset of i_cforw and i_cback must match struct vx_inode.
 */

struct vx_icache {
	struct vx_inode	*i_filler[4];	/* filler for hash chains */
	struct vx_inode	*i_cforw;	/* icache forw pointer */
	struct vx_inode	*i_cback;	/* icache back pointer */
	vx_spin_t	i_list_lk;	/* lock for this list */
	vx_u32_t	i_count;	/* count of inodes on list */
	vx_u32_t	i_gencount;	/* list generation count */
};

/*
 * The head of the various inode free/dirty lists.
 *
 * The offset of av_forw, av_back, i_dxw_forw, and i_dxw_back must
 * match struct vx_inode.
 */

struct vx_ifreehead {			/* must match struct vx_inode */
	struct vx_inode *i_filler[6];	/* filler for hash chains */
	struct vx_inode *av_forw;	/* freelist chain */
	struct vx_inode *av_back;	/* "" */
	struct vx_inode *i_dxw_forw;	/* delayed extending write list */
	struct vx_inode *i_dxw_back;	/* "" */
	vx_u32_t	i_count;	/* inodes on list */
	vx_u32_t	i_gencount;	/* list generation count */
	vx_spin_t	i_freelist_lk;	/* lock freelist and ident hash */
	struct vx_ifreehead *i_next;	/* chain of all freelists */
};

/*
 * Inode list for inodes under reorg. Used during replay of extended operations.
 */

struct vx_ireorglist {
	struct vx_inode		*i_reorgip;
	struct vx_ireorglist	*i_next;
};

/*
 * The inode lock hash chain headers.
 */

struct vx_hilock {
	struct vx_ilock	*l_forw;	/* next lock in hash chain */
	struct vx_ilock	*l_back;	/* previous lock in hash chain */
	vx_spin_t	*l_lhash_lkp;	/* lock for this hash chain */
};

/*
 * The inode hash chain headers.
 */

struct vx_hinode {		/* must match struct vx_inode */
	struct vx_inode	*i_forw;
	struct vx_inode	*i_back;
	struct vx_inode	*i_bforw;
	struct vx_inode	*i_bback;
	struct vx_ifreehead *i_identlock; /* lock for ident hash chain */
	vx_spin_t	*i_bhash_lkp;	  /* lock for block hash chain */
};

/*
 * I/O statistics for (device) files.
 */

struct vx_iostat {
	vx_u32_t	nreads;		/* Number of reads */
	vx_u32_t	nblksread;	/* Number of blocks read */
	vx_u32_t	nwrites;	/* Number of Writes */
	vx_u32_t	nblkswrite;	/* Number of blocks written */
	vx_sec_t	readtime;	/* Total time required for nreads */
	vx_sec_t	writetime;	/* Total time required for nwrites */
	vx_u32_t	ngetpages;	/* Total no of getpages */
	vx_u32_t	ndiskio;	/* Total no of diskio */
	vx_u32_t	ncreated;	/* Total no of pages created */
	vx_u32_t	npulls;		/* Number of pulls */
	vx_u32_t	nblkspull;	/* Number of blocks pulled */
	vx_u32_t	nlpushes;	/* Number of logged pushes */
	vx_u32_t	nblkslpush;	/* Number of blocks log-pushed */
	vx_u32_t	ndpushes;	/* Number of disk pushes */
	vx_u32_t	nblksdpush;	/* Number of blocks disk-pushed */
};

#define i_nreads	i_iostat.nreads
#define i_nwrites	i_iostat.nwrites
#define i_nblksread	i_iostat.nblksread
#define i_nblkswrite	i_iostat.nblkswrite
#define i_readtime	i_iostat.readtime
#define i_writetime	i_iostat.writetime
#define i_ngetpages	i_iostat.ngetpages
#define i_ndiskio	i_iostat.ndiskio
#define i_ncreated	i_iostat.ncreated
#define i_npulls	i_iostat.npulls
#define i_nblkspull	i_iostat.nblkspull
#define i_nlpushes	i_iostat.nlpushes
#define i_nblkslpush	i_iostat.nblkslpush
#define i_ndpushes	i_iostat.ndpushes
#define i_nblksdpush	i_iostat.nblksdpush

/*
 * state for delxwri flushing threads.
 */

struct vx_delxwri_state {
	struct vx_inode	*nextip;
	vx_sec_t	this_time;
	vx_sec_t	next_time;
	int		next_count;
};

/*
 * The extent structure.
 */

struct vx_extent1 {
	vx_off_t	ex1_off;	/* offset of extent in file */
	vx_off_t	ex1_sz;		/* size of extent in bytes */
	vx_daddr_t	ex1_st;		/* start block of extent */
	vx_u32_t	ex1_flags;	/* flags */
	vx_daddr_t	ex1_elen;	/* fixed extent size if
					   a multi extent run */
	vx_devid_t	ex1_dev;	/* devid of extent */
	struct vx_fset	*ex1_fset;	/* fset where extent was found */
};

struct vx_extent2 {
	vx_off_t	ex2_lbno;	/* logical start block
					   buffer within file */
	vx_u32_t	ex2_boff;	/* offset within buffer */
	vx_u32_t	ex2_bsz;	/* size of buffer */
	vx_daddr_t	ex2_bst;	/* start block of buffer */
};

struct vx_extent {
	struct vx_extent1	ex1;
	struct vx_extent2	ex2;
};

/*
 * flags for ex_flag
 */

#define	VX_EXF_NEW		0x0001	/* extent is newly allocated */
#define	VX_EXF_EXTEND		0x0002	/* OK to extend previous extent */
#define	VX_EXF_CHANGED		0x0004	/* data changed for an extent */

#define	ex_off		ex1.ex1_off
#define	ex_sz		ex1.ex1_sz
#define	ex_st		ex1.ex1_st
#define	ex_flag		ex1.ex1_flags
#define	ex_elen		ex1.ex1_elen
#define	ex_dev		ex1.ex1_dev
#define	ex_fset		ex1.ex1_fset
#define	ex_bufoff	ex2.ex2_boff
#define	ex_bufsz	ex2.ex2_bsz
#define	ex_bufbno	ex2.ex2_bst
#define	ex_buflbno	ex2.ex2_lbno

/*
 * Structures for fancy read ahead.
 */

#define VX_NRAPATT	15
#define VX_NRAHIST	(VX_NRAPATT * 2)

struct vx_rahist {
	off_t	rah_off;
};

struct vx_rapatt {
	vx_off_t	rap_off;	/* offset of next read */
	vx_off_t	rap_nextio;	/* where to start more i/os */
	vx_off_t	rap_endio;	/* end of where we've started i/o to */
	off_t		rap_stride;	/* distance between reads */
	vx_u32_t	rap_ralen;	/* how much i/o to do next */
	int		rap_count;	/* how many reads have matched patt */
	int		rap_ueread;	/* unexpected reads */
};

struct vx_radata {
	struct vx_radata	*rad_freelist;
	struct vx_rahist	rad_hist[VX_NRAHIST];
	struct vx_rapatt	rad_patt[VX_NRAPATT];
	struct vx_rapatt	*rad_lastpatt;
	int			rad_nexthist;
	int			rad_nextpatt;
};

/*
 * The incore inode structure.
 */

struct vx_inode {
	struct vx_inode	*i_forw;	/* inode hash chain */
	struct vx_inode *i_back;	/* inode hash chain */
	struct vx_inode *i_bforw;	/* inode block hash chain */
	struct vx_inode *i_bback;	/* inode block hash chain */
	struct vx_inode *i_cforw;	/* inode cache chain */
	struct vx_inode *i_cback;	/* inode cache chain */
	struct vx_inode *av_forw;	/* freelist chain */
	struct vx_inode *av_back;	/* freelist chain */
	struct vx_inode *i_dxw_forw;	/* delayed extending write list */
	struct vx_inode *i_dxw_back;	/* delayed extending write list */
	struct vx_mlinkhd i_blink;	/* head of buffer mlinks */
	struct vx_mlinkhd i_dlink;	/* head of logged write mlinks */
	struct vx_mlinkhd i_mlink;	/* head of inode modification mlinks */
	struct vx_mlinkhd i_alink;	/* async iupdate mlinks */
	struct vx_inode *i_aupd;	/* async iupdate linked list */
	vx_u32_t	i_flag;		/* flags - see below */
	vx_u32_t	i_sflag;	/* flags protected by inode spin lock */
	vx_u32_t	i_intrflag;	/* flags touched at interrupt time */
	vx_off_t	i_nsize;	/* "new" bytes in file for IDELXWRI */
	vx_off_t	i_wsize;	/* size of file if write suceeds */
	vx_off_t	i_dsize;	/* max possible inode size on disk */
	vx_dev_t	i_dev;		/* device where inode resides */
	vx_ino_t	i_number;	/* inode number */
	struct vx_fset *i_fset;		/* fileset associated with this inode */
	struct vx_fs   *i_fs;		/* fs associated with this inode */
	struct vx_ias  *i_ias;		/* inode address space pointer */
	struct vx_fsetid *i_fsi;	/* fileset identity struct ptr */
	struct vx_fsext	*i_fsext;	/* external (immovable) fs pointer */
	vx_u32_t	i_advise;	/* advisories */
	vx_off_t	i_ndblocks;	/* number of blocks in direct extents */
	vx_off_t	i_diroff;	/* dir offset where last entry found */
	vx_ino_t	i_lastino;	/* last inode allocated into directory*/
	vx_u32_t	i_dirstamp;	/* timestamp from dir search */
	struct vx_extent1 i_ext;	/* last extent for bmap cache */
	vx_tranid_t	i_tranid;	/* tran id for logged write flushing */
	vx_tranid_t	i_max_lwrid;	/* tran id of last logged write tran */
	vx_off_t	i_nextr;	/* expected offset of next read */
	vx_off_t	i_nextio;	/* offset of next read ahead I/O point*/
	vx_off_t	i_raend;	/* offset where read ahead area ends */
	struct vx_radata *i_radata;	/* data for fancy read prediction */
	vx_off_t	i_nextw;	/* expected offset of next write */
	vx_off_t	i_wflush;	/* offset of last write flush point */
	vx_off_t	i_wsyncflush;/* offset of last sync write flush point */
	vx_off_t	i_lastflushoff;	/* offst of last completed write flush*/
	vx_off_t	i_nextfault;	/* next fault expected on vnode */
	vx_off_t	i_rflush;    /* offset of last read free behind point */
	vx_u32_t	i_ralen;	/* length of read ahead area */
	vx_u16_t	i_nodealloc_idxw; /* block inode dealloc delxwri lock */
	vx_u16_t	i_nodealloc_icache; /* block inode dealloc icache lock*/
	vx_u16_t	i_inreuse;	/* block vx_itryhold references */
	vx_daddr_t	*i_swapmap;	/* block map for a swap file */
	vx_u16_t	i_unused;	/* count of procs reading the file */
	vx_u16_t	i_swmap;     /* file may have shared writable mappings*/
	vx_u32_t	i_swapcnt;	/* number times used as swap file */
	vx_u32_t	i_mapcnt;	/* count of procs mapping the file */
	vx_u32_t	i_afree;	/* free space in attribute area */
	caddr_t		i_attr;		/* pointer to attribute area */
	vx_u32_t	i_aclcnt;	/* acl count */
	vx_u32_t	i_daclcnt;	/* default acl count */
	vx_u32_t	i_iaclcnt;	/* count of acls to inherit */
	vx_u32_t	i_acllink;	/* flag for linking directory acls */
	vx_u32_t	i_modemask;	/* inheritance permission mask */
	vx_u32_t	i_attrlen;	/* length of attribute area */
	vx_daddr_t	i_bno;		/* ilist block - in sectors */
	vx_u32_t	i_boff;		/* offst of disk inode in ilist buffer*/
	vx_u32_t	i_blen;		/* length of ilist buffer */
	struct vx_icache *i_icache;	/* icache chain */
	struct vx_ifreehead *i_freelist; /* freelist inode currently on */
	struct vx_ifreehead *i_ilist;	/* inode freelist/ident hash lock */
	struct vx_hinode    *i_bhash;	/* block hash chain head */
	struct vx_hilock    *i_lhash;	/* lock hash chain head */
	vx_u32_t	i_pageflushes;	/* blocks of outstanding write flush */
	vx_sec_t	i_ftime;	/* time inode put on freelist */
	vx_sec_t	i_sizetime;	/* time of last size upd for delxwri */
	vx_u32_t	i_trangen;	/* generation count of transactions */
	vx_u32_t	i_agen;		/* access generation count */
	uint		i_vcode;	/* version code attribute */
	struct vx_dquot *i_dquot[VX_MAXQUOTAS]; /* quota information */
	struct vnode	*i_vnode;	/* vnode associated with this inode */
	struct vx_inode	*i_push;	/* inode push chain */
	struct vx_bmapops *i_bops;	/* bmap ops */
	vx_u32_t	i_dxwgencnt;	/* saved gen count for dxw list */
	struct vx_icommon i_ic;		/* disk inode */
	vx_spin_t	i_intrlock;	/* interrupt lock */
	vx_spin_t	i_spinlock;	/* inode spin lock */
	vx_sleep_t	*i_ilock;	/* inode lock */
	vx_rwsleep_t	*i_plock;	/* putpage lock */
	vx_rwsleep_t	*i_bmaplock;	/* bmap lock */
	struct vx_ilock	*i_slocks;	/* shared inode locks */
	vx_u32_t	i_hsm_change;	/* HSM_ */
	struct kdm_vnode i_hsm_kvnode;	/* HSM_ */
	caddr_t		i_hsm_attr;	/* HSM_ */
	vx_u32_t	i_hsm_attrlen;	/* HSM_ */
	int		i_ueread;	/* unexpected read count */
	vx_u32_t	i_lmode;	/* lock mode */
	vx_u32_t	i_qioadvise;	/* cached quick i/o or not */
	struct vx_iostat i_iostat;	/* i/o statistics for fdd */
};

#define VX_KDM_ITOV(ip)		((struct kdm_vnode *)&(ip)->i_hsm_kvnode)
#define VX_KDM_VTOI(kp)		((struct vx_inode *)(kp)->kdv_data)

/*
 * Aliases for the disk inode fields.
 */

#define	i_mode		i_ic.ic_mode
#define	i_nlink		i_ic.ic_nlink
#define	i_uid		i_ic.ic_uid
#define	i_gid		i_ic.ic_gid
#define	i_size		i_ic.ic_size.vh_value

#define	i_atime		i_ic.ic_atime
#define	i_mtime		i_ic.ic_mtime
#define	i_ctime		i_ic.ic_ctime

#define	i_aflags	i_ic.ic_aflags
#define	i_orgtype	i_ic.ic_orgtype
#define	i_eopflags	i_ic.ic_eopflags
#define	i_eopdata	i_ic.ic_eopdata

#define	i_rdev		i_ic.ic_ftarea.ic_ftarea_dev.ic_rdev
#define	i_dotdot	i_ic.ic_ftarea.ic_ftarea_dir.ic_dotdot
#define	i_dflags	i_ic.ic_ftarea.ic_ftarea_dir.ic_dflags
#define	i_fixextsize	i_ic.ic_ftarea.ic_ftarea_reg.ic_fixextsize
#define	i_reserve	i_ic.ic_ftarea.ic_ftarea_reg.ic_reserve
#define	i_matchino	i_ic.ic_ftarea.ic_ftarea_vxspec.ic_matchino
#define	i_fsetindex	i_ic.ic_ftarea.ic_ftarea_vxspec.ic_fsetindex

#define	i_blocks	i_ic.ic_blocks
#define	i_gen		i_ic.ic_gen
#define	i_lversion	i_ic.ic_vversion.vh_low
#define	i_hversion	i_ic.ic_vversion.vh_high
#define	i_vversion	i_ic.ic_vversion

#define	i_immed		i_ic.ic_org.ic_vx_immed.ic_immed

#define	i_ies		i_ic.ic_org.ic_vx_e4.ic_ies
#define	i_ie		i_ic.ic_org.ic_vx_e4.ic_ie
#define	i_dext		i_ic.ic_org.ic_vx_e4.ic_dext

#define	i_td4		i_ic.ic_org.ic_td4
#define	i_td8		i_ic.ic_org.ic_td8

#define	i_iattrino	i_ic.ic_iattrino

/*
 * flags in i_flag
 */

#define	IUPD		0x00000001	/* file has been modified */
#define	IACC		0x00000002	/* inode access time to be updated */
#define	IMOD		0x00000004	/* inode has been modified */
#define	ICHG		0x00000008	/* inode has been changed */
#define	IATIMEMOD	0x00000010	/* atime modified */
#define	IMTIMEMOD	0x00000020	/* mtime modified */
#define	ITRANLAZYMOD	0x00000040	/* transaction lazy mod */
#define INOCLONE	0x00000080	/* inode does not need push inode */
#define	ISYNCWRITES	0x00000100	/* file has had O_SYNC writes */
#define	IINTRANS	0x00000200	/* inode is in a transaction */
#define	IDELBUF		0x00000400	/* inode has pending delayed buffers */
#define	IGHOST		0x00000800	/* inode is a ghost attribute */
#define	ISHRDATA	0x00001000	/* don't delete data extents */
#define	INOTIMEMOD	0x00002000	/* no time update on invis i/o */
#define	ILOGWRITELOCK	0x00004000	/* inode in logged write transaction */
#define IBADHOLD	0x00008000	/* bad inode but can't idrop */

/*
 * flags in i_intrflag
 */

#define	IDELXWRI	0x0001		/* inode has delxwri data */
#define	ILOGWRITE	0x0002		/* inode has pending logged writes */
#define	IDELAYEDERR	0x0004		/* delayed update error occurred */
#define	IASYNCUPD	0x0008		/* async inode write in progress */
#define	IDATAIOERR	0x0010		/* inode had a data i/o error */

/*
 * flags in i_sflag
 */

#define	IADDRVALID	0x00000001	/* bmap has validated address map */
#define	IBAD		0x00000002	/* inode is bad */
#define	IUEREAD		0x00000004	/* getpage did an unexpected read */
#define	INOBMAPCACHE	0x00000008	/* bmap cache is disabled */
#define	IBADUPD		0x00000010	/* must be marked bad to disk */
#define	IPUTTIME	0x00000020	/* B_FORCE putpage mtime update */
#define	IATTRREM	0x00000040	/* remove attribute on inactive */
#define	INOBMAPCLUSTER	0x00000080	/* prevent bmap from clustering */
#define	IDEVACC		0x00000100	/* update access time on dev/fifo */
#define	IDEVUPDCHG	0x00000200	/* update mod/chg time on dev/fifo */
#define	IXWRITE		0x00000400	/* file has been written flag */
#define	IWRITEMAP	0x00000800	/* file has writable mappings */
#define	IDEVICE		0x00001000	/* file being accessed as device */
#define	ILASTPAGEZEROED	0x00002000	/* last page has been zeroed */

/*
 * flags in i_qioadvise
 */

#define FDD_ADVISEMASK	0x0001
#define FDD_READCACHE	0x0001		/* Cached QIO enabled on this file */

/*
 * Misc clone flags
 */

#define	VX_EOVERLAY	0x0001		/* Setup the next overlay inode */
#define	VX_EPUSH	0x0002		/* Setup the push inode */

/*
 * Iget flags
 */

#define	VX_IG_AFLAG	0x0001		/* Set full fsck flag indication */

/*
 * Iaccess flags
 */

#define	VX_DIRINSERT	1		/* Inserting a directory entry */
#define	VX_DIRDELETE	2		/* Deleting a directory entry */

/*
 * File types for which BSD quotas may be enforced.
 */

#define	VX_BSD_QUOT	(IFIFO | IFCHR | IFBLK | IFDIR | IFREG | IFLNK | \
			 IFSOC | IFATT | IFIAT)

/*
 * Convert between inode pointers and vnode pointers
 */

#define	VX_VTOI(vp)	((struct vx_inode *)(void *)(vp)->v_data)
#define	VX_ITOV(ip)	((ip)->i_vnode)

/*
 * Convert from a vnode or inode to an external file system struct.
 */

#define VX_VTOEXT(vp)	(VX_VTOI(vp)->i_fsext)
#define VX_ITOEXT(ip)	((ip)->i_fsext)

/*
 * Force any delayed writes on the inode to complete.
 */

#define	VX_DELBUF_FLUSH(ip) {					\
	if ((ip)->i_flag & IDELBUF) {				\
		vx_delbuf_flush(ip);				\
	}							\
}

#define VX_PUSH_LOGFLUSH(ip, off, len) {			\
	if ((ip)->i_dlink.ml_forw != (struct vx_mlink *)&(ip)->i_dlink) { \
		vx_push_logflush(ip, off, len);			\
	}							\
}

#define	VX_LOGWRI_FLUSH(ip) {					\
	if ((ip)->i_intrflag & ILOGWRITE) {			\
		vx_logwrite_flush(ip);				\
	}							\
}

#define VX_NODATA_FLUSH(ip) {					\
	if ((ip)->i_fsi) {					\
		VX_LOGWRI_FLUSH(ip);					\
		if (((ip)->i_fsi->fsi_flags & VX_FSI_NODATA) &&		\
		    ((ip)->i_mode & IFMT) == IFREG) {		\
			vx_nodata_flush((ip)->i_fs, (ip));\
		}							\
	} else {						\
		TED_ASSERT("f:VX_NODATA_FLUSH:33b", 		\
			(ip)->i_dlink.ml_forw ==		/*TED_*/\
			(struct vx_mlink *)&(ip)->i_dlink);	/*TED_*/\
	}							\
}

#define	VX_DELXWRI_FLUSH(ip) {					\
	if ((ip)->i_intrflag & IDELXWRI) {			\
		vx_idelxwri_flush((ip), 0, 1);			\
	}							\
}

#define	VX_DELXWRI_FLUSH_ASYNC(ip) {				\
	if ((ip)->i_intrflag & IDELXWRI) {			\
		vx_idelxwri_flush((ip), B_ASYNC, 1);		\
	}							\
}

#define VX_DELXWRI_FLUSH_ASYNC_NOLOCK(ip) {			\
	if ((ip)->i_intrflag & IDELXWRI) {			\
		vx_idelxwri_flush((ip), B_ASYNC, 0);		\
	}							\
}

/*
 * Find advisories in effect for current process
 */

#define	VX_ADVISEGET(ip)	((ip)->i_advise)

/*
 * Clean up advisories on close
 *
 * When this macro is invoked in vx_inactive(), the reference count
 * should be 1 (invoked by vx_inactive() as the last reference is
 * being released) or 0 (invoked by vx_idrop()).
 */

#define	VX_ADVISECLOSE(ip) {					\
	XTED_ADVISECLOSE(ip);					\
	(ip)->i_advise = 0;					\
}

/*
 * Put an inode on the cache list.
 */

#define	VX_IPCACHE(icp, ip) {					\
	(icp)->i_cback->i_cforw = (ip);				\
	(ip)->i_cforw = (struct vx_inode *)(icp);		\
	(ip)->i_cback = (icp)->i_cback;				\
	(icp)->i_cback = (ip);					\
	(icp)->i_count++;					\
	(ip)->i_icache = (icp);					\
}

/*
 * Remove an inode from the cache list.
 */

#define	VX_IUNCACHE(ip) {					\
	(ip)->i_cback->i_cforw = (ip)->i_cforw;			\
	(ip)->i_cforw->i_cback = (ip)->i_cback;			\
	(ip)->i_cforw = 0;					\
	(ip)->i_cback = 0;					\
	(ip)->i_icache->i_count--;				\
	(ip)->i_icache = NULL;					\
}

/*
 * Put an inode on the end of the free list.
 */

#define	VX_IPFREE(ip) {						\
	XTED_IPFREE(ip);					\
	(ip)->i_ftime = vx_lbolt;				\
	(ip)->i_freelist->av_back->av_forw = (ip);		\
	(ip)->av_forw = (struct vx_inode *)(ip)->i_freelist;	\
	(ip)->av_back = (ip)->i_freelist->av_back;		\
	(ip)->i_freelist->av_back = (ip);			\
	(ip)->i_freelist->i_count++;				\
	VX_INFO_ADD(vxi_icache_inuseino, -1);			\
	VX_MPCNTR(activeinodes, -1);				\
}

/*
 * Put an inode on the front of the free list.  Set i_ftime to be
 * the older of vx_iclean_timelag + 1 seconds ago or the i_ftime
 * of the inode currently at the head of the list.
 */

#define	VX_IPFFREE(ip) {					\
	XTED_IPFREE(ip);					\
	(ip)->i_ftime = (((ip)->i_freelist->av_forw ==		\
			 (struct vx_inode *)(ip)->i_freelist) ||\
			 ((ip)->i_freelist->av_forw)->i_ftime >	\
			 (vx_lbolt - vx_iclean_timelag - 1)) ?	\
			 (vx_lbolt - vx_iclean_timelag - 1) :	\
			 ((ip)->i_freelist->av_forw)->i_ftime;	\
	(ip)->i_freelist->av_forw->av_back = (ip);		\
	(ip)->av_back = (struct vx_inode *)(ip)->i_freelist;	\
	(ip)->av_forw = (ip)->i_freelist->av_forw;		\
	(ip)->i_freelist->av_forw = (ip);			\
	(ip)->i_freelist->i_count++;				\
	VX_INFO_ADD(vxi_icache_inuseino, -1);			\
	VX_MPCNTR(activeinodes, -1);				\
}

/*
 * Remove an inode from the freelist.
 */

#define	VX_IUNFREE(ip) {					\
	XTED_IUNFREE(ip);					\
	(ip)->av_back->av_forw = (ip)->av_forw;			\
	(ip)->av_forw->av_back = (ip)->av_back;			\
	(ip)->av_forw = 0;					\
	(ip)->av_back = 0;					\
	(ip)->i_freelist->i_count--;				\
	(ip)->i_freelist = NULL;				\
	(ip)->i_ftime = 0;					\
	VX_INFO_ADD(vxi_icache_inuseino, 1);			\
	VX_MPCNTR(activeinodes, -1);				\
}

/*
 * Put an inode on a hash list.
 */

#define	VX_IPHASH(hip, ip) {					\
	(hip)->i_forw->i_back = (ip);				\
	(ip)->i_forw = (hip)->i_forw;				\
	(hip)->i_forw = (ip);					\
	(ip)->i_back = (struct vx_inode *)(hip);		\
}

/*
 * Remove an inode from its hash list.  To allow multiple calls,
 * the forward and back hash pointers point back to the inode.
 */

#define	VX_IUNHASH(ip) {					\
	(ip)->i_back->i_forw = (ip)->i_forw;			\
	(ip)->i_forw->i_back = (ip)->i_back;			\
	(ip)->i_forw = (ip);					\
	(ip)->i_back = (ip);					\
}

/*
 * Put an inode on a block hash list.
 */

#define	VX_IPBHASH(hip, ip) {					\
	(hip)->i_bforw->i_bback = (ip);				\
	(ip)->i_bforw = (hip)->i_bforw;				\
	(hip)->i_bforw = (ip);					\
	(ip)->i_bback = (struct vx_inode *)(hip);		\
}

/*
 * Remove an inode from its block hash list.  To allow multiple calls,
 * the forward and back hash pointers point back to the inode.
 */

#define	VX_IUNBHASH(ip) {					\
	(ip)->i_bback->i_bforw = (ip)->i_bforw;			\
	(ip)->i_bforw->i_bback = (ip)->i_bback;			\
	(ip)->i_bforw = (ip);					\
	(ip)->i_bback = (ip);					\
}

/*
 * Put an inode lock on a hash list.
 */

#define	VX_LPHASH(hlp, lp) {					\
	(hlp)->l_forw->l_back = (lp);				\
	(lp)->l_forw = (hlp)->l_forw;				\
	(hlp)->l_forw = (lp);					\
	(lp)->l_back = (struct vx_ilock *)(hlp);		\
}

/*
 * Remove an inode lock from its hash list.
 */

#define	VX_LRHASH(lp) {						\
	(lp)->l_back->l_forw = (lp)->l_forw;			\
	(lp)->l_forw->l_back = (lp)->l_back;			\
	(lp)->l_forw = (lp);					\
	(lp)->l_back = (lp);					\
}

/*
 * Hash an inode.
 */

#define	VX_HASH(seed, key)	((seed) + (key) * 523)

#define	VX_IHASH(seed, key)	(vx_hinode + \
				 (VX_HASH((seed), (key)) & (vx_nhino - 1)))

#define	VX_LHASH(seed, key)	(vx_hilock + \
				 (VX_HASH((seed), (key)) & (vx_nhino - 1)))

union vx_ipargs {
	struct vx_ipchkver {
		vx_hyper_t		version;
	} ipchkser;
	struct vx_ipquotacheck {
		struct vx_fset		*fset;
		vx_u32_t		type;
		vx_uid_t		*newidlist;
		vx_u32_t		newidcount;
		vx_u32_t		newidlimit;
		vx_u32_t		dqheld;
	} ipquotacheck;
};

/*
 * This overlays the fid structure (see mount.h).
 */

struct vx_vfid {
	vx_u16_t	vfid_len;
	vx_ino_t	vfid_ino;
	vx_u32_t	vfid_gen;
};

#define	MAKEIMODE(x, y) ((vx_vttoif(x)) | ((y) & (IFMT | 0xfff)))

/*
 * Structure used by resize to keep track of changes to structural inodes.
 */

struct vx_rsi {
	struct vx_inode	*rsi_ip;
	vx_off_t		rsi_osize;
	vx_off_t		rsi_nsize;
};

/*
 * The attribute code that modifies attributes, particular the attribute
 * inheritance code, requires a number of inode locks.  Some must be
 * appropriately cleaned up/reacquired when a transaction commits and
 * all must be released when the operation completes (an operation may
 * require multiple transactions).
 *
 * See vx_attr.c for a description of attribute locking.  The fields
 * are arranged in the order that locks are acquired.  All non_NULL
 * fields represent inodes that are held and locked.  The locks are:
 *
 * Field	Lock	Explanation
 *
 * vt_dirinip	rwlock	indirect attribute inode for "parent" inode
 * vt_preinip	rwlock	pre-existing indirect attribute inode for target
 * vt_preaip	rwlock	pre-existing attribute inode for target
 * vt_newaip	ilock	newly allocated (or modified) attribute inode
 *			for target
 * vt_newinip	ilock	newly allocated (or modified) indirect attribute
 *			inode for target
 * vt_oldaip	none	an old attribute inode removed in the transaction
 *
 * vt_preinip and vt_newinip may refer to the same inode, if it was
 * pre-existing and modified in the transaction.  vt_preaip and
 * vt_newaip may also refer to the same inode, typically when the
 * inode requires a multi-transaction allocation.
 */

struct vx_attrlocks {
	struct vx_inode *vt_dirinip;	/* directory (parent) indirect inode */
	struct vx_inode *vt_preinip;	/* pre-existing indirect inode */
	struct vx_inode	*vt_preaip;	/* pre-existing attribute inode */
	struct vx_inode	*vt_newaip;	/* new attribute inode */
	struct vx_inode	*vt_newinip;	/* new indirect attribute inode */
	struct vx_inode *vt_oldaip;	/* old (removed) attribute inode */
};

/*
 * Parameters passed through dircreate for inheritance.
 */

struct vx_inherit {
	struct vx_attrlocks	vh_alocks;	/* attribute locks */
	struct vx_inode		*vh_linklist[5]; /* attr inodes linked */
	vx_u32_t		vh_nlink;	/* num of entries */
	struct vx_tran		*vh_tranp;	/* current transaction */
	vx_u32_t		vh_onetran;	/* fast inheritance */
	uid_t			vh_uid;		/* uid to be allocated */
	gid_t			vh_gid;		/* gid to be allocated */
	vx_u32_t		vh_tranbytes;	/* tranbytes needed */
};

#define	VX_PUBLIC_CLASS	1000	/* classes below 1000 are reserved */

/*
 * Class and subclass fields are of type 32 bit unsigned. Class ids
 * in range of (vx_32_t)-999 to 999 are now reserved. The unsignedness
 * of class/subclass invalidates the check for negative ids, however,
 * there are set of attribute tests that specify negative class ids
 * and expect failure. Until we change the attribute test suite not
 * to test with negative class ids, we'll reject any 'reserved' class
 * ids in range of (vx_u32_t)-999 to (vx_u32_t)-1 (used by fsqa test
 * suite) as invalid negative classes.
 */

#define VX_PUBLIC_CLASS_MIN	(vx_u32_t)-999	/* smallest resevered class id*/
#define VX_PUBLIC_CLASS_MAX	(vx_u32_t)999	/* largest resevered class id */
#define VX_MAX_CLASS		(vx_u32_t)-999	/* maximum class id */
#define VX_INVALID_CLASS(class)	((class) >= VX_MAX_CLASS)

#define	VX_ATTR_IGNORE	1	/* Don't allow operation to see attribute */
#define	VX_ATTR_KEEP	2	/* Perform operation as requested */
#define	VX_ATTR_NEW	3	/* Substitute new attribute data */
#define	VX_ATTR_LINK	4	/* Link to parent attribute */

struct vx_attrop {
		/* Listing/Reading attributes */
	int	(*aop_listop) __P((struct vx_inode *, vx_u32_t, vx_u32_t,
				   vx_ino_t, caddr_t, vx_u32_t, caddr_t *,
				   vx_u32_t *, vx_u32_t *, vx_cred_t *));
		/* Setting/Removing attributes */
	int	(*aop_changeop) __P((struct vx_inode *, struct vx_inode *,
				     vx_u32_t, vx_u32_t, vx_u32_t, caddr_t,
				     vx_u32_t, caddr_t *, vx_u32_t *,
				     vx_u32_t *, vx_cred_t *));
		/* Inheriting attributes */
	int	(*aop_creatop) __P((struct vx_inode *, struct vx_inode *,
				    vx_u32_t, vx_ino_t, caddr_t, vx_u32_t,
				    caddr_t *, vx_u32_t *, struct vx_inode **,
				    vx_u32_t *, struct vx_inherit *,
				    vx_cred_t *, struct vattr *));
		/* New attributes on file create */
	int	(*aop_newop) __P((struct vx_inode *, struct vx_inode *,
				  vx_u32_t *, vx_ino_t, caddr_t *, vx_u32_t *,
				  vx_u32_t *, struct vx_inherit *,
				  vx_cred_t *));
};

struct vx_attrreg {
	struct vx_attrreg	*ar_next;	/* next registered class */
	vx_u32_t		ar_class;	/* registered class */
	struct vx_attrop	ar_aops;	/* attribute operations */
	struct vx_attrreg	*ar_newop_next;	/* next class with newop */
};

#define	VX_NREGHASH	64	/* num of hash chains of registered classes */

/*
 * Structure to control multi-threaded processing of flushing.
 */

struct vx_flushargs {
	struct vx_flushargs	*fa_pnext;	/* next pointer */
	vx_event_t		fa_done_ev;	/* done event */
	vx_s32_t		fa_result;	/* error code */
	void			*fa_private1;	/* first arg to function */
};

/*
 * Structure to control multi-threaded inode cache traversals.
 */

struct vx_icacheargs {
	struct vx_icacheargs	*ica_pnext;	/* next pointer */
	struct vx_icache	*ica_icp;	/* icache list to process */
	vx_event_t		ica_done_ev;	/* done event */
	vx_s32_t		ica_result;	/* error code */
	void			*ica_private1;	/* first arg to function */
	void			*ica_private2;	/* second arg to function */
	void			*ica_private3;	/* third arg to function */
	void			*ica_private4;	/* fourth arg to function */
};

/*
 * This structure controls work items for threads.  A work thread should
 * take an item off the worklist queue and process it.
 */

struct vx_worklist {
	struct vx_worklist	*wl_next;		/* next work item */
	struct vx_worklist	*wl_prev;		/* prev work item */
	void			(*wl_workfunc) __P((void *));
							/* function to call */
	void			*wl_args;		/* args to function */
	vx_u32_t		wl_tag;			/* ID tag */
};

#endif	/* _FS_VXFS_VX_INODE_H */
