/*
 *	IBM/Microsoft Confidential
 *
 *	Copyright (c) IBM Corporation 1987, 1989
 *	Copyright (c) Microsoft Corporation 1987, 1989
 *
 *	All Rights Reserved
 *
 *	SCCSID = @(#)mft.h	6.5 91/07/26
 *
 *	Converted from mft.h by bryand, Dec 7, 1989
 *
 */

/* XLATOFF */
#pragma title("Internal Master File Table Format")
/* XLATON  */

/**	OS/2 MFT definitions
 *
 *  The Master File Table (MFT) associates the cannonicalized pathnames, lock
 *  records and SFTs for all files open on this machine.
 *
 *  The MFT implementation employs a Patricia Tree (PTree) (radix tree)
 *  (in a BMP32 object) with pointers to the actual MFT entries (allocated
 *  off the swappable heap).  This means that all access to the MFT
 *  need to use FLATCONTEXT and 32 bit overrides, or be 32 bit code.
 *  Touching an MFT entry can block as they are swappable.  This is
 *  new for v20 so we have to be careful that blocking is OK.
 *
 *	MFT PTree
 *	===========
 *  The MFT PTree is used to lookup and store the path strings.
 *  This is much faster than the old singly linked list.
 *  The tree nodes are managed by BMP32.  Each node has a pointer to
 *  the corresponding MFT entry.
 *
 *	MFT Entries
 *	===========
 *  The MFT entries are allocated from the swappable heap.
 *
 *	RLR Entries
 *	===========
 *  The RLR (record lock record) segment contains fixed format records
 *  containing record locking information. This is managed by BMP.
 */

#define MFT_MAX_NODES	16000	// max number of MFT entries (open files)

#define MFT_PATTERN	"Fm"	// signature for mft
#define MFT_PAT_DEL	0xbad1	// signature for mft being deleted

typedef struct MFT_Entry {
    KSEMSHR	mft_ksem;	// multi read/single write semaphore
    ushort_t	mft_lptr;	// 16 bit offset to first LOCK record
    ulong_t	mft_sptr;	// 16 bit FAR  pointer to first SFT in chain
    ulong_t	mft_pCMap;	// 32 bit FLAT pointer to cluster map
    KSEMSHR	mft_CMapKSem;	// semaphore for access to pCMap
    ushort_t	mft_opflags;	// oplock flags
    ushort_t	mft_serl;	// serial number for FCB checking
    ushort_t	mft_flags;	// general purpose MFT flags
#ifdef FSSTRICT
    ushort_t	mft_signature;	// for sanity check
#endif
    ushort_t	mft_hvpb;	// handle of vpb
    uchar_t	mft_name;	// start of name string (zero terminated)
} MFT_Entry;

#define mft_key	mft_hvpb	// start of key for tree search

// Flags for mft_flags field.

#define mft_pagerheap  0x0001	    // 0 - MFT is allocated on kernel heap
				    // 1 - MFT is allocated on pager heap

#define MFT_DEFAULTHEAP 0x0	    // default MFT heap

// Flags for mft_opflags field.

#define mft_opnolock	0		// no oplock or opbatch on file
#define mft_oplock	1		// oplock on file
#define mft_opbatch	2		// opbatch on file
#define mft_opanylock	(mft_oplock | mft_opbatch)	// oplock or opbatch
#define mft_opbreak	4		//oplock/batch cleanup in process
#define mft_opbreakfailed 8		// oplock/batch cleanup failed


/*	Record Lock Record (RLR):
 */

typedef struct RLR_Entry {
    ushort_t	rlr_next;	// 16 bit offset to next RLR.  0 if end
    ushort_t	rlr_prev;	// 16 bit offset to prev RLR.  0 if SFT
    ulong_t	rlr_fba;	// offset of first byte of locked region
    ulong_t	rlr_lba;	// offset of last  byte of locked region
    ulong_t	rlr_sptr;	// 16:16  FAR  pointer to SFT
    ushort_t	rlr_UID;	// lock issuer's user ID
    ushort_t	rlr_PID;	// lock issuer's process ID
    ushort_t	rlr_PDB;	// lock issuer's PDB, 0 for non-3xBox
    uchar_t	rlr_flags;	// flags
} RLR_Entry;

/*  When a thread blocks because of a lock conflict, the
 *  pending lock is chained to a doubly-linked list of pending locks.
 *  The head  of this list is kept in the SFT.
 *
 *  When a lock is pending, some fields are redefined as follows:
 */

#define rlr_block   rlr_UID	/* offset of lock we're blocked on   */
#define rlr_handle  rlr_PDB	/* handle requesting this lock	     */


#define RLR_INCR	10	// grow this many entries at a time

/* ASM
RLRCONTEXT	macro	sr
	push	GSEL GDT_RLR
	pop	sr
	ASSUME	sr:nothing
endm
*/

// Flag bits in lock record

#define RLR_EXCLUSIVE	0
#define RLR_SHARED	1
#define RLR_WAITING	2
#define RLR_CANCELPLOCK 4

// Internal Error Codes

#define RLR_LENGTH_ERROR	0
#define RLR_VIOLATION_ERROR	1

/* Access Bits
 *
 * When Clr_Block wants to clear a lock range we don't want to return an error
 * if his lock range conflicts with a lock he already owns. So, other callers
 * of SLE set the RLR_FIND_OWN flag to indicate that they want to know about
 * conflicts even if they own the lock.
 */

// If the access desired is Read the RLR_READ_ACCESS flag is set.

#define RLR_WRITE_ACCESS	1
#define RLR_READ_ACCESS		2
#define RLR_FIND_OWN		4
#define RLR_ATO_OVER    8


/*  Cluster Map (mft_pCMap points to one of these)
 *
 *	  16	   16	   16	   16		  16		  16
 *    +--------+--------+-------+-------+~~~+------------+~~~+------------+
 *    | iValid | iAlloc | clu 0 | clu 1 |   | clu iValid |   | clu iAlloc |
 *    +--------+--------+-------+-------+~~~+------------+~~~+------------+
 *			 \_____________	 _______________/ \______  ______/
 *				       \/			 \/
 *			       valid cluster data	    unfilled data
 *
 *  The cluster map is used to store the cluster chain for an open file.  The
 *  cluster map is allocated the first time the File System tries to chase
 *  the cluster chain for the file (SKPCLP in rom.asm).  The cluster map is
 *  grown on demand as the File System accesses points in the file past
 *  the clusters stored in the cluster map.  If the cluster map cannot be
 *  grown, cluster chain scanning occurs, but the clusters found are not
 *  stored in the map.
 *
 *  The largest cluster number is FFFF.
 *  The smallest cluster number that is part of a file chain
 *  is 2 (The FAT entries for clusters 0 and 1 are used for the
 *  media information).  So, (FFFF-2+1) = FFFE clusters = 1FFFC
 *  bytes for a file that maps an entire disk.  The cluster map
 *  is allocated from the kernel 32 bit heap.  If we decide to
 *  allocate it from the swappable heap, we will have to special
 *  case the cluster map for the swap file.
 *  It is convienient to put the header info in the first two
 *  words of the cluster map as clusters 0 and 1 are reserved.
 *
 *  cm_iValid	ordinal of the last cluster in the file for which we have valid
 *		data in the cluster map (FFFD max).
 *
 *  cm_iAlloc	ordinal of the entry at end of the allocated space (FFFD max).
 *
 *  cm_iAlloc >= cm_iValid;
 */

typedef struct ClusMap {
    ushort_t	cm_iValid;	// index of last valid cluster
    ushort_t	cm_iAlloc;	// index of last allocated cluster map entry
    ushort_t	cm_map;		// first entry in cluster map
} ClusMap;


/*  A pictorial diagram for the linkages is as follows:
 *
 *	   +---sptr------+
 *	   V		 |
 *	 +---+<----------|---sptr------+------------+
 *	 |SFT+----+	 |	       |	    |
 *	 +-+-+	  |    +-+-+	    +--+-+	 +--+-+
 *	   V	  +--->|MFT+-lptr->-|LOCK+-next->|LOCK+->0
 *	 +---+	  |    +---+	    +----+	 +----+
 *	 |SFT+----+	 ^  \
 *	 +-+-+		 |   \		   +--------+
 *	   |		 |    +-selCMap--->|ClusMap1|
 *	   +-------------+    |		   +--------+
 *			      +-selCMap2-->|ClusMap2|
 *					   +--------+
 */


/**	Interesting behavior that should be noted:
 *
 *	The sharer must maintain information on files in three forms:
 *
 *	local/remote handles.  These are normal handles and behave in no
 *	    strange manner.  They are identified by SF_mode not having the
 *	    sfIsFCB flag nor by having the sf_mode = 70.  No problems with
 *	    locking.  No problems with open.  No problems with close.
 *	    CloseByName will iterate closes until the mft disappears.
 *	    CloseUser will iterate closes until no SFT for the particular user
 *	    appears.  CloseProcess will iterate closes until no SFT for the
 *	    particular user/process appears.
 *
 *	local FCBs.  There are no corresponding SFT's for these as the SFTs
 *	    are cached but will be valid for the particular file.  There is
 *	    one SFT for each open on a file by a specific process.  These are
 *	    identified the sfIsFCB flag in the sf_mode field.  When multiple
 *	    opens occur, we merely find the sf pertinent to the file and
 *	    process.  Close decrements the ref count.  CloseByName, CloseUser,
 *	    CloseProcess will iterate closes until no more SFTs exist.
 *
 *	handles with mode 70.  These represent FCB's open across the network.
 *	    As such, identical sfts may have been collapsed by the $open code.
 *	    This results in a reuse of the same SFT.  The $Open code must
 *	    correctly set the ref-count for the sft to reflect the number of
 *	    collapses that have occurred.  These are identified by a 70 in the
 *	    SF_mode field.  There can be no locking on these SFTs.  Open must
 *	    scan the list of SFTs for the file and increment its ref count
 *	    appropriately.
 */
