/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos72X src/bos/kernel/j2/include/j2_dmap.h 1.17.1.11                   */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 1999,2020              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/* @(#)85       1.17.1.11  src/bos/kernel/j2/include/j2_dmap.h, sysj2, bos72X, x2020_50B3 12/4/20 11:28:06 */
/*
 * COMPONENT_NAME: (SYSJ2) JFS2 Physical File System
 *
 * FUNCTIONS:
 *
 * ORIGINS: 27
 *
 * (C) COPYRIGHT International Business Machines Corp. 1996, 1999
 * All Rights Reserved
 * Licensed Materials - Property of IBM
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */

#ifndef	_H_J2_DMAP
#define _H_J2_DMAP	

#include <j2/j2_types.h>

#ifdef _KERNEL
#include <j2/j2_cntl.h>
#include <j2/j2_inode.h>
#include <j2/j2_txnmgr.h>
#include <sys/errno.h>
#endif	/*  _KERNEL */

#define BMAPVERSION	1		/* version number                    */
#define	TREESIZE	(256+64+16+4+1)	/* size of a dmap tree 		     */
#define	LEAFIND		(64+16+4+1)	/* index of 1st leaf of a dmap tree  */
#define LPERDMAP	256		/* num leaves per dmap tree 	     */
#define L2LPERDMAP	8		/* l2 number of leaves per dmap tree */
#define	DBWORD		32		/* # of blks covered by a map word   */
#define	L2DBWORD	5		/* l2 # of blks covered by a mword   */
#define BUDMIN  	L2DBWORD	/* max free string in a map word     */
#define BPERDMAP	(LPERDMAP * DBWORD)	/* num of blks per dmap	     */
#define L2BPERDMAP	13		/* l2 num of blks per dmap           */
#define CTLTREESIZE	(1024+256+64+16+4+1)  /* size of a dmapctl tree      */
#define CTLLEAFIND	(256+64+16+4+1)	/* idx of 1st leaf of a dmapctl tree */
#define LPERCTL		1024		/* num of leaves per dmapctl tree    */
#define L2LPERCTL	10		/* l2 num of leaves per dmapctl tree */
#define	ROOT		0		/* index of the root of a tree	     */
#define	NOFREE		((int8) -1) 	/* no blocks free	             */
#define	MAXAG		128		/* max number of allocation groups   */
#define L2MAXAG		7		/* l2 max num of AG */
#define L2MINAGSZ	25		/* l2 of minimum AG size in bytes */
#define	BMAPBLKNO	0		/* lblkno of bmap within the map     */

/*
 * maximum l2 number of disk blocks at the various dmapctl levels.
 */
#define	L2MAXL0SIZE	(L2BPERDMAP + 1 * L2LPERCTL)
#define	L2MAXL1SIZE	(L2BPERDMAP + 2 * L2LPERCTL)
#define	L2MAXL2SIZE	(L2BPERDMAP + 3 * L2LPERCTL)

/*
 * maximum number of disk blocks at the various dmapctl levels.
 */
#define	MAXL0SIZE	((int64)1 << L2MAXL0SIZE)
#define	MAXL1SIZE	((int64)1 << L2MAXL1SIZE)
#define	MAXL2SIZE	((int64)1 << L2MAXL2SIZE)

#define	MAXMAPSIZE	MAXL2SIZE	/* maximum aggregate map size	     */

/* 
 * determine the maximum free string for four (lower level) nodes
 * of the tree.
 */
#define	TREEMAX(cp)					\
	((signed char)(MAX(MAX(*(cp),*((cp)+1)),	\
	                   MAX(*((cp)+2),*((cp)+3)))))

/*
 * convert disk block number to the logical block number of the dmap
 * describing the disk block.  s is the log2(number of logical blocks per page)
 *
 * The calculation figures out how many logical pages are in front of the dmap.
 *	- the number of dmaps preceding it
 *	- the number of L0 pages preceding its L0 page
 *	- the number of L1 pages preceding its L1 page
 *	- 3 is added to account for the L2, L1, and L0 page for this dmap
 *	- 1 is added to account for the control page of the map.
 */
#define BLKTODMAP(b,s)    \
        ((((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) << (s))

/* DMAP metadata pages are always 4K */
#define BLKTODMAPN(b) 	  \
    	BLKTODMAP(b, 0)

/*
 * convert the number of filesystem blocks to the number of pages
 * in the filesystem block map.
 *
 * The input b is the number of filesystem blocks that the map must cover.
 * We subtract 1 from b because BLKTODMAPN uses an index to do its calculation.
 * The output of BLKTODMAPN for this calculation is the page number of the
 * last page of the block map.  We add 1 to this because the number of pages
 * is the last page number plus one.
 */
#define DMAPBLOCKS(b)     \
        BLKTODMAPN((b - 1)) + 1

/*
 * convert disk block number to the logical block number of the LEVEL 0
 * dmapctl describing the disk block.  s is the log2(number of logical blocks
 * per page)
 *
 * The calculation figures out how many logical pages are in front of the L0.
 *	- the number of dmap pages preceding it
 *	- the number of L0 pages preceding it
 *	- the number of L1 pages preceding its L1 page
 *	- 2 is added to account for the L2, and L1 page for this L0
 *	- 1 is added to account for the control page of the map.
 */
#define BLKTOL0(b,s)      \
        (((((b) >> 23) << 10) + ((b) >> 23) + ((b) >> 33) + 2 + 1) << (s))

/*
 * convert disk block number to the logical block number of the LEVEL 1
 * dmapctl describing the disk block.  s is the log2(number of logical blocks
 * per page)
 *
 * The calculation figures out how many logical pages are in front of the L1.
 *	- the number of dmap pages preceding it
 *	- the number of L0 pages preceding it
 *	- the number of L1 pages preceding it
 *	- 1 is added to account for the L2 page
 *	- 1 is added to account for the control page of the map.
 */
#define BLKTOL1(b,s)      \
     (((((b) >> 33) << 20) + (((b) >> 33) << 10) + ((b) >> 33) + 1 + 1) << (s))

/*
 * convert disk block number to the logical block number of the dmapctl
 * at the specified level which describes the disk block.
 */
#define BLKTOCTL(b,s,l)   \
        (((l) == 2) ? (1<<(s)) : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s)))

/* 
 * convert aggregate map size to the zero origin dmapctl level of the
 * top dmapctl.
 */
#define	BMAPSZTOLEV(size)	\
	(((size) <= MAXL0SIZE) ? 0 : ((size) <= MAXL1SIZE) ? 1 : 2)

/* convert disk block number to allocation group number.
 */
#define BLKTOAG(b,ip)	((b) >> ((ip)->i_ipmnt->i_ipbmap->i_bmap->db_agl2size))

/* convert allocation group number to starting disk block
 * number.
 */
#define AGTOBLK(a,ip)	\
	((int64)(a) << ((ip)->i_ipmnt->i_ipbmap->i_bmap->db_agl2size))

#define L0SPACING (LPERCTL + 1)
#define L1SPACING (L0SPACING * LPERCTL)

/*
 * Check whether given bmap page number is for a control page (any level).
 * Pages 0, 1, 2, 3 are control pages at the start of the bmap.
 * L1 pages are ((LPERCTL + 1) * LPERCTL) pages apart, starting at page 2.
 * L0 pages are (LPERCTL + 1) pages apart, starting at page 3. Each additional L1
 * page shifts the L0 pages by 1, so that number has to be subtracted.
 */ 
#define ISCTLPG(p) \
	(((p) < 4) || \
	 (((p) - 2) % (L1SPACING + 1) == 0) || \
	 ((((p) - 3 - (((p) - 3) / L1SPACING)) % L0SPACING) == 0))

/*
 * Calculate first filesystem block described by the given bmap page number.
 * The number of L0 and L1 pages before this page are subtracted, similar to
 * ISCTLPG above, to give us the count of how many regular pages came before
 * this one; each of those pages maps BPERDMAP blocks.
 */
#define BMAPSTARTBLK(p) \
	((int64)(((p) < 4) ? 0 : (((p) - 4 - \
	  (((p) - 4 - (((p) - 4) / L1SPACING)) / L0SPACING) - \
	  (((p) - 3) / (L1SPACING + 1)) \
	 ) << L2BPERDMAP)))

/*
 *	dmap summary tree
 *
 * dmaptree_t must be consistent with dmapctl_t.
 */
typedef struct {
	int32	nleafs;		/* 4: number of tree leafs		   */
	int32	l2nleafs;	/* 4: l2 number of tree leafs		   */
	int32	leafidx;	/* 4: index of first tree leaf		   */
	int32	height;		/* 4: height of the tree		   */
	int8	budmin;		/* 1: min l2 tree leaf value to combine	   */
	int8	stree[TREESIZE];/* TREESIZE: tree			   */
	uint8	pad[2];		/* 2: pad to word boundary		   */
} dmaptree_t;			/* - 360 -				   */

/*
 *	dmap page per 8K blocks bitmap
 */
typedef struct {
	int32		nblocks;	/* 4: num blks covered by this dmap */
	int32		nfree;		/* 4: num of free blks in this dmap */
	int64		start;		/* 8: starting blkno for this dmap  */
	dmaptree_t	tree;		/* 360: dmap tree                   */
	uint8		pad[1672];	/* 1672: pad to 2048 bytes          */
	uint32		wmap[LPERDMAP];	/* 1024: 8192 bits of the working map    */
	uint32		pmap[LPERDMAP];	/* 1024: 8192 bits of the persistent map */
} dmap_t;				/* - 4096 -                         */

/*
 *	disk map control page per level.
 *
 * dmapctl_t must be consistent with dmaptree_t.
 */
typedef struct {
	int32		nleafs;		/* 4: number of tree leafs          */
	int32		l2nleafs;	/* 4: l2 number of tree leafs       */
	int32		leafidx;	/* 4: index of the first tree leaf  */
	int32		height;		/* 4: height of tree		    */
	int8		budmin;		/* 1: minimum l2 tree leaf value    */
	int8		stree[CTLTREESIZE]; /* CTLTREESIZE: dmapctl tree    */
	uint8		pad[2714];	/* 2714: pad to 4096                */
} dmapctl_t;				/* - 4096 -                         */

/*
 *	common definition for dmaptree_t within dmap and dmapctl
 */
typedef	union {
	dmaptree_t	t1;
	dmapctl_t	t2;
} dmtree_t;
	
/* macros for accessing fields within dmtree_t */
#define	dmt_nleafs	t1.nleafs
#define	dmt_l2nleafs 	t1.l2nleafs
#define	dmt_leafidx 	t1.leafidx
#define	dmt_height 	t1.height
#define	dmt_budmin 	t1.budmin
#define	dmt_stree 	t1.stree

/* 
 *	on-disk aggregate disk allocation map descriptor.
 */
typedef struct {
	int64		dn_mapsize;		/* 8: number of blocks in aggregate  	*/
	int64		dn_nfree;		/* 8: num free blks in aggregate map 	*/
	int32		dn_l2nbperpage;		/* 4: l2 num of blks per page        	*/
	int32		dn_numag;		/* 4: total number of ags            	*/
	int32		dn_maxlevel;		/* 4: max bmap control level 	     	*/
	int32		dn_maxag;		/* 4: max active alloc group number     */
	int32		dn_agpref;		/* 4: preferred alloc group (hint)   	*/
	int32		dn_aglevel;		/* 4: dmapctl level holding the AG   	*/
	int32		dn_agheight;		/* 4: height in dmapctl of the AG    	*/
	int32		dn_agwidth;		/* 4: width in dmapctl of the AG     	*/
	int32		dn_agstart;		/* 4: start tree index at AG height  	*/
	int32		dn_agl2size;		/* 4: l2 num of blks per alloc group 	*/
	int64		dn_agfree[MAXAG];  	/* 8*MAXAG: per AG free count     	*/
	int64		dn_agsize;		/* 8: num of blks per alloc group    	*/
	int8		dn_maxfreebud;		/* 1: max free buddy system	     	*/
	uint8		reserved[7];		/* 7: reserved for future use 	     	*/
	int64   	dn_lockedmap_start; 	/* 8: index of first bmap page locked	*/
	int64		dn_lockedmap_num; 	/* 8: number of bmap pages locked 	*/
	uint8		pad[2984];		/* 2984: pad to 4096                 	*/
} dbmap_t;					/* - 4096 -                          	*/

/* convert log2 leaf value to buddy size */
#define	BUDSIZE(s,m)		(1 << ((s) - (m)))

#ifdef _KERNEL
/* 
 *	in-memory aggregate disk allocation map descriptor.
 */
typedef struct bmap {
	dbmap_t		db_bmap;	/* on-disk aggregate map descriptor  */
	inode_t		*db_ipbmap;	/* ptr to aggregate map incore inode */
	MUTEXLOCK_T	db_bmaplock;	/* aggregate map lock		     */
	uint32		*db_DBmap;
} bmap_t;

/* macros for accessing fields within in-memory aggregate map descriptor */
#define	db_mapsize		db_bmap.dn_mapsize
#define	db_nfree		db_bmap.dn_nfree
#define	db_agfree		db_bmap.dn_agfree
#define	db_agsize		db_bmap.dn_agsize
#define	db_agl2size		db_bmap.dn_agl2size
#define	db_agwidth		db_bmap.dn_agwidth
#define	db_agheight		db_bmap.dn_agheight
#define	db_agstart		db_bmap.dn_agstart
#define	db_numag		db_bmap.dn_numag
#define	db_maxlevel		db_bmap.dn_maxlevel
#define	db_aglevel		db_bmap.dn_aglevel
#define	db_agpref		db_bmap.dn_agpref
#define	db_maxag		db_bmap.dn_maxag
#define	db_maxfreebud		db_bmap.dn_maxfreebud
#define	db_l2nbperpage		db_bmap.dn_l2nbperpage
#define db_lockedmap_start 	db_bmap.dn_lockedmap_start
#define db_lockedmap_num 	db_bmap.dn_lockedmap_num

/* Backward compatability for old typo */
#define db_agheigth	db_agheight		
#define dn_agheigth	dn_agheight

/*
 * macros for various conversions needed by the allocators.
 * blkstol2(), cntlz(), and cnttz() are operating system dependent functions.
 */
/* convert number of blocks to log2 number of blocks, rounding up to
 * the next log2 value if blocks is not a l2 multiple.
 */
#define	BLKSTOL2(d)		(log2up64(d))

/* convert number of leafs to log2 leaf value */
#define	NLSTOL2BSZ(n)		(31 - clz32((n)) + BUDMIN)

/* convert leaf index to log2 leaf value */
#define	LITOL2BSZ(n,m,b)	((((n) == 0) ? (m) : ctz32((n))) + (b))

/* convert a block number to a dmap control leaf index */
#define BLKTOCTLLEAF(b,m)	\
	(((b) & (((int64)1 << ((m) + L2LPERCTL)) - 1)) >> (m))

/* Count the number of leading allocated bits in the specified word. */
#define	CTALLOC(word)		(clz32(~(word)))

/*
 *	external references.
 */
int32 dbMount(inode_t *ipbmap);

int32 dbUnmount(inode_t *ipbmap, uint32	mounterror);

int32 dbSync(inode_t *ipbmap);

int32 dbUpdatePMap(inode_t *ip, int32 free, int64 blkno, int64 nblocks,
	tblock_t *tblk);

int32 dbFree(inode_t *ipbmap, int64 blkno, int64 nblocks);

int32 dbNextAG(inode_t *ipbmap);

int32 dbAlloc(inode_t *ipbmap, int64 hint, int64 nblocks, int64 *results);
int32 _dbAlloc(inode_t *ipbmap, int64 hint, int64 nblocks, int64 *results);

int32 dbAllocExact(inode_t *ip, int64 blkno, int32 nblocks);
int32 dbAllocExactOnly(inode_t *ip, int64 blkno, int32 nblocks);

int32 dbAllocAnyAndReserve(inode_t *ip, int64 nblocks, int8 l2nb, int64 *results);

int32 dbFindCtl(bmap_t *mp, int8 l2nb, int32 level, boolean_t rbna, int64 *blkno);

int32 dbFindLeaf(dmtree_t *tp, int8 l2nb, int32 *leafidx, bmap_t *mp);

int32 dbReAlloc(inode_t *ipbmap, int64 blkno, int64 nblocks, int64 addnblocks,
	int64 *results);

int32 dbExtend(inode_t *ip, int64 blkno, int64 nblocks, int64 addnblocks);

int32 dbAllocBottomUp(inode_t *ip, int64 blkno, int64 nblocks);
int32 dbResizeFS(inode_t *ipbmap, int64 blkno, int64 nblocks, int32 flag);
int32 dbFinalizeBmap(inode_t *ipbmap, int32 flag);
int64 dbMapFileSizeToMapSize(inode_t *ipbmap);

reg_t dbReserve(inode_t	*ip, int64 nBlocks, boolean_t mdata);
void dbCancel(  inode_t *ip, int64 nBlocks);
int32 j2_extentInfo(struct vfs *vfsp, caddr_t pData, int32 lenData,
			struct ucred *crp);
int32 j2_dbUsedPhysBlocks(inode_t *ipmnt, struct j2PhysRangeAlloc *j2PRA);
int32 dbRelocateBMap(inode_t *ipbmap, int64 xfence, int64 *nBlockToMove, int64 *nBlockMoved);
int32 dbFreePWMap(inode_t *ipbmap, int64 blkno, int32 nblocks);
int32 dbFreeBMap(inode_t *ipbmap, int64 xeof, int64 xfence);
int32 dbTruncateBMap(inode_t *ipbmap, int64 xeof, int64 *nBlocks);
int32 dbScanBitMap(dmap_t  *dp, int64 start, int32 nblocks);
int32 dbLockMap(inode_t *ip, int64 lockstart, int64 locknum);

_inline int
dbRelocateAlloc(inode_t *ipmap, int64 hint, int64 xlen, int64 *dxaddr, 
								int64 xfence)
{
	int 	rc = 0;

	if (rc = dbAlloc(ipmap, hint, xlen, dxaddr))
		return rc;
	
	if (*dxaddr + xlen > xfence)
	{
		/* free space outside of fence */
		dbFree(ipmap, *dxaddr, xlen);
		rc = ENOSPC;
	}

	return rc;
}

/* Flag to dbResizeFS function */
#define EXTENDFS	0x00000001
#define SHRINKFS	0x00000002

#define dbUnlockMap(_IPBMAP) dbLockMap(_IPBMAP, -1, 0)

#endif /* _KERNEL */
#endif	/* _H_J2_DMAP */