/*	@(#)fx.h	13.1 (RC International) 91/02/02	*/

/*
 *  fx.h -- primary file system space management structures
 *
 * Each logical volume contains exactly one file system.
 * A file system consists of a number of allocation units.
 * Each allocation unit has inodes and data.
 *
 * A file system is described by its super-block, which in turn
 * describes the allocation units.  The super-block is critical
 * data and is replicated in each allocation unit to protect against
 * catastrophic loss.  This is done at mkfs time and the critical
 * super-block data does not change, so the copies need not be
 * referenced further unless disaster strikes.
 *
 * For file system fx, the offsets of the various blocks of interest
 * are given in the super block as:
 *	[fx->fx_sblkno]		Super-block
 *	[fx->fx_aublkno]	Allocation unit block
 *	[fx->fx_iblkno]		Inode blocks
 *	[fx->fx_dblkno]		Data blocks
 * The beginning of allocation unit au in fx, is given by
 * the ``AUBASE(fx, au)'' macro.
 */

#define SBSIZE		1024
#define	SBLOCK		((daddr_t)(0))

/*
 * Addresses stored in i-nodes address extents.  Extents are made up of
 * some number of blocks which is a power of two.  The block size is
 * a parameter of the logical volume.
 *
 * The root inode is the root of the file system.
 * Inode 0 can't be used for normal purposes and
 * historically bad blocks were linked to inode 1,
 * thus the root inode is 2. (inode 1 is no longer used for
 * this purpose, however numerous dump tapes make this
 * assumption, so we are stuck with it)
 * The lost+found directory is given the next available
 * inode when it is created by ``mkfx''.
 */

#define	ROOTINO		((ino_t)2)	/* i number of all roots */
#define LOSTFOUNDINO	(ROOTINO + 1)

/*
 * Allocation unit related limits.
 */

#define MAXBPU		(DEV_BSIZE * NBBY)

/*
 * MAXIPU bounds the number of inodes per allocation unit, and
 * is needed only to keep the structure simpler by having the
 * only a single variable size element (the free bit map).
 *
 * N.B.: MAXIPU must be a multiple of INOPB(fx).
 */

#define	MAXIPU		2048	/* max number inodes/alloc unit */

#define MINBSIZE	DEV_BSIZE

/*
 * The path name on which the file system is mounted is maintained
 * in fx_fxmnt. MAXMNTLEN defines the amount of space allocated in 
 * the super block for this name.
 */

#define MAXMNTLEN 512

/*
 * The extent bit-map is logically divided into two sections - the
 * single block map and the multi-block map.  Each of these two sections
 * is (obviously) the same size.
 */

#define EMAPBLKS	2

/*
 * We assume here that DEV_IOSIZE is the same as MAXBSIZE, a
 * spectacularly bad assumption.  Due to the design of the multi-
 * tiered bit-map, if 1024-byte blocks are used, there are 14 tiers
 * in the map, which spans two logical blocks.
 */

#define NTIERS	(DEV_BSHIFT + 4)

#define ISBIT(emap, bit) ( emap[(bit) / NBBY] & (1 << ((bit) % NBBY)) )

#define BIT_IN_TIER(b, t)	((b) >> (t))

struct tier_descriptor
{
    short	t_emapblk;		/* relative block within emap */
    short	t_bitoffset;		/* from start of block */
    short	t_nextents;		/* tier length in bits */
    short	t_extsize;		/* number of blocks (not bytes) */
};


/*
 * Per allocation unit information; one per au block plus
 * one in the fx block which contains system-wide totals.
 * As of TX5, only us_ndir is maintained on disk (too hard to recompute)
 * all the other fields are recomputed at mount time.
 */

struct usum
{
    long	us_ndir;		/* number of allocated directories */
    long	us_nifree;		/* number of free inodes */
    long	us_nefree[NTIERS];	/* numbers of free extents */
};

struct fx_list
{
    struct fx_list	*fxl_next;
    ino_t		fxl_ino;
    daddr_t		fxl_bn;
};

/*
 * Super block for a file system.
 */

#define	FX_MAGIC	0x011955
#define FX_BSHIFT	DEV_BSHIFT
#define FX_BMASK	(DEV_BSIZE - 1)

/*  values for fx_flags */
#define FX_LOGWRAPPED	0x01		/* log has wrapped around */
#define FX_SYNCED	0x02		/* fs sync has occured */
#define FX_UNMOUNT	0x04		/* file system is unmounting */
#define FX_BLOCK_OPENS	0x08		/* file system is unmounting */
#define FX_UMASK	0x0c		/* unmount masks */
#define FX_RECOVERY	0x10		/* recovery in progress */

/*
 * struct to keep track of indir blocks in memory.
 * A list is maintained from the super block
 */

struct indir
{
    int			in_blkno;
    struct indir	*in_next;
};
	
struct fx
{
    long	fx_magic;		/* magic number */
    long	fx_version;		/* file system version */
    struct fx	*fx_link;		/* linked list of file systems */
    struct fx	*fx_rlink;		/*     used for incore super blocks */
    daddr_t	fx_sblkno;		/* addr of super-block in filesys */
    daddr_t	fx_aublkno;		/* offset of au-block in filesys */
    daddr_t	fx_eblkno;		/* offset of emap block(s) in filesys */
    daddr_t	fx_iblkno;		/* offset of inode-blocks in filesys */
    daddr_t	fx_dblkno;		/* offset of first data after au */
    daddr_t	fx_dupoffset;		/* displacement of dup. control blks */
    UID_T	fx_uniqueid;		/* unique i.d. of this file system  */
    time_t 	fx_time;    		/* last time written */
    long	fx_size;		/* number of blocks in fx */
    long	fx_dsize;		/* number of data blocks in fx */
    long	fx_nau;			/* number of allocation units */
    long	fx_bsize;		/* size of basic blocks in fx */
/* these are configuration parameters */
    long	fx_minfree;		/* minimum percentage of free blocks */
    long	fx_maxbpu;		/* max number of blks per alloc unit */
/* these fields can be computed from the others */
    long	fx_sbsize;		/* actual size of super block */
    long	fx_nindir[NIADDR];	/* values of NINDIR */
    long	fx_inopb;		/* value of INOPB */
    long	fx_sparecon[5];		/* reserved for future constants */
/* time of last mount */
    time_t	fx_mount_time;
/* sizes determined by number of allocation units and their sizes */
    long	fx_dbpu;		/* data blocks per allocation unit */
/* these fields can be computed from the others */
    long	fx_ipu;			/* inodes per alloc unit */
    long	fx_bpu;			/* blocks per alloc unit */
/* this data must be re-computed after crashes */
    long	fx_blocksfree;
    struct usum	fx_ustotal;	/* alloc unit summary information */
/* these fields are set at create time */
    char   	fx_sysv;    		/* File system uses SYSV semantic */
/* these fields are cleared at mount time */
    char   	fx_clean;    		/* file system is clean flag */
    char   	fx_ronly;   		/* mounted read-only flag */
    char   	fx_flags;   		/* keeps in-memory flags */
    char	fx_fxmnt[MAXMNTLEN];	/* name mounted on */
/* these fields retain the current block allocation info */
    long	fx_aurotor;		/* last au searched */
/* these fields are used in memory only, and have no meaning on disk */
    struct usum		*fx_usp;	   /* array ptr of fx_us info buffers */
    struct inode 	*fx_lvp;	   /* in-core ptr to lv descriptor */
    struct bufhdr 	*fx_bufp;	   /* back pointer to fx block bufhdr */
    struct fx_list 	*fx_deletepending; /* inodes waiting to be closed */
    struct fx_list 	*fx_holdlist;	   /* blocks awaiting dealloc */
/* what to audit in this file system */
    unsigned int	fx_aud;		   /* flag for what to audit */
/* these fields are used in memory only, and have no meaning on disk */
    int			fx_unused2;	   /* unused */
    int			fx_unused3[2];	   /* unused */
    int 		fx_unused4;	   /* unused */
    int 		fx_unused5;	   /* unused */
    int 		fx_lgsn;	   /* last log serial number */
    int			fx_sync;	   /* Have we seen the sync */
/* These fields are mainatined on disk */
    int			fx_ptier;	   /* default primary extent */
    int			fx_stier;	   /* default secondary extent */
/* These fields are memory only */
    struct indir	*fx_indir;	   /* list of accessed indir blocks */
    time_t		fx_dumpdate[10];   /* last dump of each level */
    int			fx_dumpfreq;	   /* days between dumps */
    logsn_t		fx_start_lsn;	   /* start recovery block lsn */
    int			fx_start_rec;	   /* start recovery record in blk */
    logsn_t		fx_cur_lsn;	   /* current start recovery lsn */
    int			fx_cur_rec;	   /* current recovery record in blk */
    UID_T		fx_dev_t;	   /* uid to maintain a unique dev_t */
/* padding to 1024 bytes */
    int			fx_padding[43];	   /* unused */
};


/*
 * Allocation unit block for a file system.
 */

#define	AU_MAGIC	0x090256

struct au
{
    long	au_magic;		/* magic number */
    struct au	*au_link;		/* linked list of alloc units */
    struct au	*au_rlink;		/*     used for incore alloc units */
    time_t	au_time;		/* time last written */
    long	au_aun;			/* we are the aun'th allocation unit */
    long	au_bpu;			/* number of total blocks this au */
    short	au_niblk;		/* number of inode blocks this au */
    short	au_spare;
    long	au_ndblk;		/* number of data blocks this au */
    long	au_unused[NTIERS];	/* Not used anymore */
    long	au_ndir;		/* number of free inodes */
    long	au_irotor;		/* position of last used inode */
    char	au_iused[MAXIPU/NBBY];	/* used inode map */
    char	*au_emap[EMAPBLKS];	/* ptrs to in-core emap blocks */
    bool_t	au_emapchg[EMAPBLKS];	/* for flagging changes to map blocks */
    unsigned int au_sum0;		/* hash sum */
    unsigned int au_sum1;		/* hash sum */

/* actually longer */
};

/*
 * Allocation unit macros to locate things in allocation units.
 * They calc file system addresses of allocation unit data structures.
 */

#define	AUBASE(fx, c)	((daddr_t)((fx)->fx_bpu * (c)))
#define	AUSBLOCK(fx, c)	(AUBASE(fx, c) + (fx)->fx_sblkno)	/* super blk */
#define	AUTOD(fx, c)	(AUBASE(fx, c) + (fx)->fx_aublkno)	/* au block */
#define	AUTOE(fx, c)	(AUBASE(fx, c) + (fx)->fx_eblkno)	/* emap blk 1 */
#define	AUIMIN(fx, c)	(AUBASE(fx, c) + (fx)->fx_iblkno)	/* inode blk */
#define	AUDMIN(fx, c)	(AUBASE(fx, c) + (fx)->fx_dblkno)	/* 1st data */

/*
 * Macros for handling inode numbers:
 *     inode number to file system block offset.
 *     inode number to allocation unit number.
 *     inode number to file system block address.
 */

#define	ITOO(fx, x)	((x) % INOPB(fx))
#define	ITOU(fx, x)	((x) / (fx)->fx_ipu)
#define	ITOD(fx, x) \
	((daddr_t)(AUIMIN(fx, ITOU(fx, x)) + \
	(((x) % (fx)->fx_ipu) / INOPB(fx))))

/*
 * Give allocation unit number for a file system block.
 * Give allocation unit block number for a file system block.
 */

#define	DTOU(fx, d)	((d) / (fx)->fx_bpu)
#define	DTOUD(fx, d)	((d) % (fx)->fx_bpu)
#define	DTOD(fx, d)	(((d) % (fx)->fx_bpu) - (fx)->fx_dblkno)

/*
 * The following macros optimize certain frequently calculated
 * quantities by using shifts and masks in place of divisions
 * modulos and multiplications.
 */

#define BLKOFF(fx, loc)		/* calculates (loc % DEV_BSIZE) */ \
	((loc) & FX_BMASK)
#define LBLKNO(fx, loc)		/* calculates (loc / DEV_BSIZE) */ \
	((loc) >> FX_BSHIFT)
#define BLKROUNDUP(fx, size)	/* calculates roundup(size, DEV_BSIZE) */ \
	(((size) + DEV_BSIZE - 1) & FX_BMASK)

/*
 * Determine the number of available blocks given a
 * percentage to hold in reserve
 */

#define FREESPACE(fx, pctreservd) \
	((fx)->fx_blocksfree - ((fx)->fx_dsize * (pctreservd) / 100))

/*
 * INOPB is the number of inodes in a secondary storage block.
 */

#define	INOPB(fx)	((fx)->fx_inopb)

/*
 * NINDIR is the number of indirects in a file system block.
 */

#define	NINDIR(fx, level)	((fx)->fx_nindir[level])
