summaryrefslogtreecommitdiffstats
path: root/private/ntos/boot/bootcode/hpfs/i386/buf.inc
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/boot/bootcode/hpfs/i386/buf.inc')
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/buf.inc222
1 files changed, 222 insertions, 0 deletions
diff --git a/private/ntos/boot/bootcode/hpfs/i386/buf.inc b/private/ntos/boot/bootcode/hpfs/i386/buf.inc
new file mode 100644
index 000000000..fe2eb8377
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/buf.inc
@@ -0,0 +1,222 @@
+;static char *SCCSID = "@(#)buf.h 12.1 88/11/21";
+;** BUF.H - Buffer definitions
+;
+; HPFS Utilities
+; Peter A. Williams
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 08/01/89 Added typedef BUFNODE and PBUFNODE.
+;
+
+;* Buffer Nodes
+;
+; When the comments talk about "buffer address" they're always
+; talking about the buffer header address. If we're talking
+; about the address of the data field of the buffer, we say
+; "buffer data".
+;
+; These buffer headers are also used as I/O request blocks for
+; the data in the buffer. The B_IOP field contains the
+; function. Sometimes we need an I/O request block which
+; isn't assocated with a buffer - for example, when we read
+; directly into an application's memory area. For this, we keep
+; a pool of I/O request blocks which are actually BUFNODE
+; structures, but they aren't associated with a buffer and the
+; B_ADDR field is used to hold the I/O target address.
+; These BUFNODEs have BF_IORQ in the flags field to distinguish
+; them from regular buffer headers.
+;
+; Note that we use the B_SUM field for debugging purposes. This is an
+; array of SPB words, each of which holds the CAS (high and low
+; 16 bits xored togehter) of one of the sectors. We can then check
+; this value to make sure that we're setting the dirty bits
+; correctly.
+;
+; NOTE - see the discussion on holding and locking at the end of
+; this file
+;
+
+BUFNODE struc
+
+ B_LRU db (size DCHDR) dup (?) ; LRU chain, if not BF_IORQ
+ B_LRUH dd ? ; address of LRU chain head if not locked/held
+ ; if lcoked/held, we're on that chain but
+ ; this guy points to it's regular chain
+ B_SEC dd ? ; VSector #
+ B_ADDR dd ? ; address of data
+ B_DCHN db (size DCHDR) dup (?) ; doubly linked list of dirty buffers
+ B_dirt db ? ; 1 bit per dirty sector
+ ; used to optimize the write. Non dirty
+ ; marked sectors may still be rewritten
+ B_iop db ? ; disk driver I/O operation
+ B_type db ? ; type of info
+ B_FLAG db ? ; flags
+ B_HCNT dw ? ; hold count
+ B_LCNT db ? ; lock count (really a flag, only 0 or 1
+ B_BADSEC db ? ; 1 bit per defective sector
+ B_next dd ? ; advisory address of next buffer content
+ ; always a buffer header addr, never 0
+ B_DADR dd ? ; address of routine to call when I/O is done
+
+ ; The following two fields are redefined
+ ; if BF_IORQ is set.
+ B_HASH db (size DCHDR) dup (?) ; sector hash chain
+ B_HTA dd ? ; address of entry in hash table
+
+ B_WAIT dd ? ; head of wait chain
+ifdef DEBUG
+ B_SUM dw 4 dup (?) ; holds checksum of buffer contents
+else
+ B_XTRA db 8 dup (?)
+endif
+
+; 64 byte boundary
+
+ B_LDTIME dd ? ; time (in ms/512) when buffer was last dirtied
+ B_FDTIME dd ? ; time (in ms/512) when buffer got first dirtied
+ B_LWWAIT dd ? ; head of lazy write wait chain
+ B_XTRA2 db 64-16 dup (?)
+BUFNODE ends
+
+;typedef struct BUFNODE BUFNODE;
+;typedef struct BUFNODE *PBUFNODE;
+
+BUFHDRSHIFT equ 7
+
+ifdef MASM
+ .errnz (size BUFNODE) - (1 SHL BUFHDRSHIFT)
+endif
+
+; Following are alternative offsets if BF_IORQ is set
+
+B_XFER equ (DWORD PTR B_HTA) ; holds transfer sec cnt
+B_NADR equ (DWORD PTR B_HASH) ; addr of client's NOTEREC
+B_NMSK equ (DWORD PTR B_HASH+4) ; notification mask
+ifdef MASM
+ .errnz (size DCHDR)-8 ; enough room for double map
+endif
+
+; B_FLAG bits
+
+BFL_LWLOCK equ 00000001h ; buffer is being lazy written in a block
+
+
+; B_type values
+
+BF_FREE equ 0 ; buffer is free (not in LRU list)
+BF_LRU equ 1 ; buffer in LRU list
+
+
+; Priority values for LRU placement
+
+BP_KEEP equ 0 ; Buffer contains future-usable data
+BP_NOOPINION equ 1 ; Buffer contains marginally useful data
+BP_TOSS equ 2 ; Buffer is unlikely to be used
+
+; NOTEREC - Notification Record
+;
+; Some callers may post several disk requests in parallel and
+; want to keep track of when they're *all* complete. I/O
+; request blocks (buffer headers w/o buffers) have fields to
+; allow this. The caller stores the address of his NOTEREC,
+; and when each request completes it clears it's associated bit.
+; When all of the bits clear the block chain in the NOTEREC
+; is woken.
+;
+; Note that there can be only one thread blocked on a NOTEREC
+; because the first guy to wakeup will return the NOTEREC to the
+; heap or whatever. This occurs naturally; unlike I/O to the
+; buffer cache, NOTERECs are used for direct I/O. If someone
+; else wants to do I/O to the same location and if record and file
+; locking allows that, then they'll get their own NOTEREC or
+; cache I/O request and have a horse race. NOTERECs are only used
+; to do file data I/O, all "filesystem" structures are manipulated
+; via the cache.
+;
+; The fields are DWORD, but only the low byte of the MSK and FLD
+; records are used for normal completion. The 3rd byte of NTR_FLD
+; (..FF....h) is used for error posting - these bits are
+; set if an irrecoverable error occured in the I/O.
+;
+
+NOTEREC struc
+ NTR_FLD dd ? ; the mask bit field
+ NTR_BLC dd ? ; head of the block chain
+ NTR_MSK dd ? ; next bit to set in NTR_FLD
+NOTEREC ends
+
+
+;* Holding and Locking
+;
+; LOCK means that the buffer contents are inconsistant/incorrect. No body
+; is allowed to look at the contents of the buffer. This is done
+; when we're reading in from the disk; we'll mark the buffer
+; with the VSector # (so that any other folks that want that sector
+; won't issue their own reads in parallel) but we mark it LOCKED
+; so that nobody looks at it's contents which aren't correct yet.
+;
+; LOCKed is pretty rare because most folks which are mucking
+; with a buffer have it back in a consistant state before they
+; allow a context switch.
+;
+; An important exception to this is directory manipulation -
+; directory splitting, etc. In this case, a flag has been set
+; on the directory itself (in SBDIR) so that no one will try to
+; look at the directory contents. The cache block which has the
+; inconsistant DIRBLK might also have sectors belonging to someone
+; else and those sectors can be accessed by other folks because
+; the buffer isn't locked. (We don't lock the directory and not
+; the block for this reason, it's a fallout. We lock the directory
+; because it's too mucky for people to "back out" if they're
+; searching down into a directory and find out that they've
+; reached an area which is being rebuilt. The rebuilding might
+; propigate up and change the unlocked higher DIRBLKs that this
+; other guy has already accessed... So we lock the whole directory,
+; and thus needn't bother locking the cache blocks themselves.
+;
+; HOLD means that the contents are valid, but the cache block must continue
+; to hold that data. Folks use this when they need to access
+; two different sectors at the same time. They HOLD one when
+; they read the other so that there's no chance that by the
+; time the 2nd read finishes the first one has been evicted.
+; This is much cheaper than remembering the first one's VSector
+; # and calling RDBUF N times as you transfer N words of info
+; between the two sectors.
+;
+; By definition only one guy can lock a buffer (the lock count should
+; go to a flag; it's already a flag on directorys) but the hold
+; value is a count, since multiple people can hold. (Like the
+; electrician's safety plate which allows multiple electricians
+; to lock a breaker OPEN so that it can't be closed until ALL are
+; done). (SBDIRs have a hold count for the same reason - folks
+; may yield while in a directory and don't want it to change out
+; from under them)
+;
+; We also use hold when we set dirty bits. The concern is that
+; if we're going to write something to a buffer, yield the CPU,
+; then write something else, we don't want to have to make two
+; calls to SetDirt, one after each write. This costs time, and
+; also it would be a waste if the lazywriter were to write this
+; guy anyhow, since he's going to get dirty again ASAP and
+; writing him out doesn't free the cache block anyway, since it's
+; held.
+;
+; So my current algorithm is that I won't lazywrite anybody who
+; is held, and therefore won't mark them clean. This means,
+; in effect, that there is no ordering constraint on dirtying
+; a buffer or marking it dirty so long as it is held the entire
+; time. I think that the code now always marks it dirty before
+; a yield, even if held, because the debug code is a bit hard
+; assed about it, but this could be relaxed under the current
+; lazywrite rules I've just described.
+;
+; Both in the case of directorys and cache blocks, the theory is that
+; since these buffers are MRU, it's extremely rare that we'd actually try
+; to reclaim their buffer slots, and in general it's rare that there's
+; a conflict in their use. So in actual execution, these locks are
+; very rarely encountered. They're cheap - INC to set and DEC to clear,
+; so almost always all we're doing is INCing and DECing a location
+; and it's just two wasted instructions. Once in a while, though,
+; it's a big bacon save, as they say.
+;