Files
mars-nwe/include/core/include/xCache.h
2026-06-14 10:26:40 +02:00

662 lines
20 KiB
C

/****************************************************************************
|
| (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc.
| All Rights Reserved.
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of version 2 of the GNU General Public
| License as published by the Free Software Foundation.
|
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with this program; if not, contact Novell, Inc.
|
| To contact Novell about this file by physical or electronic mail,
| you may find current contact information at www.novell.com
|
|***************************************************************************
|
| NetWare Advance File Services (NSS) Initialization module
|
|---------------------------------------------------------------------------
|
| $Author: gpachner $
| $Date: 2007-07-11 05:18:49 +0530 (Wed, 11 Jul 2007) $
|
| $RCSfile$
| $Revision: 2084 $
|
|---------------------------------------------------------------------------
| This module is used to:
| Definitions used by caching.
|
| WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
|
| This header file should ONLY be used for NSS internal development.
| This includes Semantic Agents (SA) and Loadable Storage Services (LSS).
| Any other use may cause conflicts which NSS will NOT fix.
+-------------------------------------------------------------------------*/
#ifndef _XCACHE_H_
#define _XCACHE_H_
#ifndef _LATCH_H_
# include <include/latch.h>
#endif
#ifndef _QUE_H_
# include <library/que.h>
#endif
#ifndef _ALARM_H_
# include <include/alarm.h>
#endif
#ifndef _CONTROL_H_
# include <include/control.h>
#endif
#ifndef _FSM_H_
# include <include/fsm.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Pre-define struct(s) so Linux compiler doesn't complain */
struct Agent_s;
struct Pool_s;
/*
* This is here because ASYNCIO.H needs it
*/
typedef void (*AgentSignalFunc_t)(struct Agent_s *agent);
#ifndef _ASYNCIO_H_
# include <include/asyncio.h>
#endif
/*
* States for buffers:
*
* When a buffer is victim selected and is dirty, it is flushed to
* disk then put at the head of the LRU queue so it is used on the
* next cache miss.
*
* If a buffer is currently in use when you try to toss it, we defer
* the toss but do remove it from the hash list. On the last release,
* we put it at the head of the LRU queue.
*/
#define CACHE_CLEAR 0 /* No flags set */
#define CACHE_DIRTY 0x1 /* Needs to be flushed to disk */
#define CACHE_VICTIM 0x2 /* Was selected as a victim but
* was dirty and needed to be
* written. Put at front of LRU
* queue when done.
*/
#define CACHE_TOSS 0x4 /* When this cache buffer is released,
* just toss it even if it is dirty.
* (It has already been removed from
* the hash list).
*/
#define CACHE_LOG_TEST 0x8 /* Used while undo/redo testing for
* recovery to not release buffers
*/
#define CACHE_MEMORY_BUFFER 0x10 /* Used by admin volume to indicate
* whether a buffer should be flushed
* to disk or to memory.
*/
#define CACHE_ATTACHED 0x20 /* When we copy the buffer if someone
* tries to X_Latch it, while it is
* being flushed, we set this bit to
* indicate a bond has been set up
*/
#define CACHE_USER_BUFFER 0x40 /* This buffer is being used for
* user data.
*/
#define CACHE_FAKE_BUFFER 0x80 /* Used while waiting to alloc a
* cache buffer, so that another
* requesting this same buffer
* knows about it.
*/
#define CACHE_HAS_LINUX_PAGE 0x100 /* This buffer has a page associated
* with a inode that Linux is
* managing. If this buffer is not
* dirty and/or bonded, we can
* return the page to the linux
* cache and we will look for it
* there.
*/
//#define CACHE_HAS_NO_LINUX_PAGE 0x200 /* This buffer was created for a
// * for a Linux Page. But we returned
// * the page to the Linux cache. We
// * will look for the page in the
// * Linux cache and if found, associate
// * it with this buffer again.
// */
#define CACHE_STATE_INVALID 0x400
#define CACHE_DATA_VALID 0x800 /* The data in the page
* pointed to by this buffer is
* valid. No need to read from
* disk again.
*/
/*
* Access modes for cache
*/
#define CACHE_READ 0 /* Going to read -> shared access */
#define CACHE_WRITE 1 /* Going to write whole block -> exlusive */
#define CACHE_UPDATE 2 /* Going to update part of block ->exlusive */
/*-------------------------------------------------------------------------
* These structures and functions are used to setup
* dependencies between different entities. The entities
* never see the Bond_s structure but must include
* the Agent_s structure inside of themselves.
*
* The signal functionslets the agent control its behavior when all
* dependcies have been satisfied. After the specified signal function
* is finished, it should call the default signal routine.
*-------------------------------------------------------------------------*/
typedef struct Agent_s Agent_s;
/* These are values for Agent_s state */
/* the values 0xFFFF0000 are reserved for local use by the object which
* contains the agent */
#define AGENT_FLUSHING 0x0001 /* The agent wants to be flushed
*/
#define AGENT_AWAIT_SIGNALS 0x0002 /* Waiting for dependent signals
* before flushing. */
#define AGENT_WAIT_FOR_COMMIT 0x0004 /* Wait for the ZLOG buffer to which
* the EndXLocal gets written to
* commit
*/
#define AGENT_LOCAL_STATE_FLAGS 0xFFFF0000 /* The values in the high word of
* state are reserved for local use by the
* object which contains the agent */
struct Agent_s
{
FsmLite_s fsm; /* FSM for flushing agent's object */
Latch_s latch; /* Latch to synchronize flushing */
OneShot_s timer; /* One shot timer to force flushing */
STKtop_t signalList; /* List to signal after I'm flushed */
DQhead_t flushList; /* These must flush before agent can flush */
AgentSignalFunc_t signal; /* User defined signal function */
LONG numLeft; /* Count of signals I'm still waiting for that
* I already called the flush functions.
* This makes processing the flushList
* much simpler. */
NINT state; /* State: (eventually combine with numLeft) */
STATUS status; /* current status of the operation */
AgentSignalFunc_t bondFreedSignal; /* signal function when a bond is freed*/
};
typedef struct Bond_s
{
STKlink_t signalLink; /* List of objects to be signaled */
/* May be able to use a stack here */
Agent_s *toSignal; /* Object to signal after flush is done */
DQlink_t flushLink; /* Must wait until flushed */
Agent_s *toFlush; /* Object to flush */
} Bond_s;
#define MYCACHE_STATE_USING_BUFLIST 0x0001
#define MYCACHE_STATE_TRUNCATING 0x0002
#define MYCACHE_STATE_PURGING 0x0004
typedef struct MyCache_s
{
DQhead_t bufList; /* Buffers owned by beast */
Agent_s agent; /* Agent that is dependent */
BYTE bufSizeShift; /* Size file cache buffer log 2 */
BYTE reserved[1]; /* Align structure */
WORD state; /* State of the mycache */
} MyCache_s;
/*-------------------------------------------------------------------------
* This Buffer matches zBuffer_s. Any modifications made here
* should be reflected in zBuffer_s in zParams.h
* zBuffer_s specifies fileBlk to be a QUAD, and if Blknum_t
* is changed to be 64-bit, the pad from this strucuture should be
* removed
*-------------------------------------------------------------------------*/
typedef struct PubBuffer_s
{
BYTE *data; /* Place first so other layers
* can access it with out knowing
* details.
*/
MyCache_s *mycache; /* Pointer to user of cache buffer */
Blknum_t fileBlk; /* Logical block offset in file */
#if BLKNUM_64 IS_DISABLED
LONG pad;
#endif
} PubBuffer_s;
typedef struct Buffer_s
{
PubBuffer_s pBuf;
#ifdef i386
Blknum_t volBlk; /* Location in volume */
#endif
#ifdef __x86_64__
SQUAD volBlk; /* Location in volume */
#endif
Agent_s agent; /* Agent for buffer */
DQlink_t hashLink; /* Link for hash queue */
DQlink_t lruLink; /* Link for LRU list */
DQlink_t mycacheLink; /* Link to all buffers for beast*/
DQlink_t signalLink; /* Link of buffers that signals are being
* delayed on. Used by ZLOG to delay signals
* until all previous log buffers have been
* flushed.
*/
AgentSignalFunc_t writeDone;/* if non-zero, when a write completes this
* routine should be called instead of doing
* the standard processing which consists of
* calling "defaultSignal" and
* "CACHE_SIGNAL_RELEASE"
*/
LONG state; /* Misc. state bits */
BYTE reserved;
BYTE bufSizeShift; /* Size of a buffer log 2 */
BYTE ioRetryCount; /* retry count when doing writes*/
BYTE pinned; /* Current count of pins on buf */
Time_t timeStamp; /* Time stamp when buffer waa put on LRU */
struct EncryptedBufPage_s *eData; /* pointer to encrypted volume data buffer */
struct page *b_page; /* A pointer to the page associated with data */
LONG b_mapCount; /* Number of times the buffer kmap is requested */
BioReq_s bioReq;
} Buffer_s;
extern void mapBufferPage(Buffer_s *buf);
extern void unmapBufferPage(Buffer_s *buf);
extern const Buffer_s *NSSPrivateBuffer;
/*-------------------------------------------------------------------------
* The following structures and macros support asynchronous IO requests
*-------------------------------------------------------------------------*/
typedef struct Synchronize_s
{
Latch_s waitLatch; /* Used to wait for all to finish */
struct zNSSMsg_s *msg; /* Message for requests */
} Synchronize_s;
#define SYNC_INIT(_sync, _msg) \
{ \
(_sync).msg = (_msg); \
INIT_LATCH( &((_sync).waitLatch)); \
}
#define SYNC_ADD(_sync) ADD_LATCH( &((_sync).waitLatch))
#define SYNC_WAIT(_sync) \
{ \
if (IS_SLATCHED( &((_sync).waitLatch))) \
{ \
X_LATCH( &((_sync).waitLatch)); \
UNX_LATCH( &((_sync).waitLatch)); \
} \
}
extern CIRhead_t WaitForCacheQ; /* Wait queue for free buffers */
extern Latch_s ReserveBuffers; /* Used to pre-alloc buffers */
extern Buffer_s CACHE_SparseBuffer; /* Used for sparse files */
#if NSS_DEBUG IS_ENABLED
#define CACHE_RELEASE(_buf) \
(cacheRelease(_buf), ((_buf) = ((_buf)->pinned) ? (_buf) : NULL))
#define CACHE_DIRTY_RELEASE(_buf) \
(ASSERT_XLATCH( &((_buf)->agent.latch)), \
((_buf)->state |= CACHE_DIRTY), CACHE_RELEASE(_buf))
#define CACHE_MARK_DIRTY(_buf) \
cacheMarkDirty(_buf) \
#define CACHE_CLEAN(_buf) \
((_buf)->state &= ~CACHE_DIRTY)
#define CACHE_SIGNAL_RELEASE(_buf) \
(cacheSignalRelease(_buf), ((_buf) = ((_buf)->pinned) ? (_buf) : NULL))
#define CACHE_SIGNAL_RELEASE_PUSH(_buf) \
(((_buf)->state |= CACHE_VICTIM), \
cacheSignalRelease(_buf), ((_buf) = ((_buf)->pinned) ? (_buf) : NULL))
#define CACHE_SIGNAL_RELEASE_TOSS(_buf) \
(cacheSignalReleaseToss(_buf), ((_buf) = ((_buf)->pinned) ? (_buf) : NULL))
#else
#define CACHE_RELEASE(_buf) \
(cacheRelease(_buf))
#define CACHE_DIRTY_RELEASE(_buf) \
(ASSERT_XLATCH( &((_buf)->agent.latch)), \
((_buf)->state |= CACHE_DIRTY), CACHE_RELEASE(_buf))
#define CACHE_MARK_DIRTY(_buf) \
cacheMarkDirty(_buf) \
#define CACHE_CLEAN(_buf) \
((_buf)->state &= ~CACHE_DIRTY)
#define CACHE_SIGNAL_RELEASE(_buf) \
(cacheSignalRelease(_buf))
#define CACHE_SIGNAL_RELEASE_PUSH(_buf) \
(((_buf)->state |= CACHE_VICTIM), \
cacheSignalRelease(_buf))
#define CACHE_SIGNAL_RELEASE_TOSS(_buf) \
(cacheSignalReleaseToss(_buf))
#endif
#define CACHE_XLATCH(_buf) \
X_LATCH( &(_buf)->agent.latch)
#define CACHE_SLATCH(_buf) \
S_LATCH( &(_buf)->agent.latch)
#define CACHE_UNXLATCH(_buf) \
UNX_LATCH( &(_buf)->agent.latch)
#define CACHE_UNSLATCH(_buf) \
UNS_LATCH( &(_buf)->agent.latch)
#define CACHE_UNLATCH(_buf) \
UN_LATCH( &(_buf)->agent.latch)
#define POKE_SIGNAL_HANDLER(_buf, _func) \
((_buf)->agent.signal = (_func))
#define CACHE_PIN(_buf) (++((_buf)->pinned))
#define CACHE_UNPIN(_buf) \
((void)(zASSERT((_buf)->pinned != 0),((--(_buf)->pinned) || cacheUnpinned(_buf))))
extern void initMyCache(
MyCache_s *mycache,
AgentSignalFunc_t signal,
NINT bufSizeShift,
char *name);
extern void checkMyCache(
MyCache_s *mycache);
extern void cacheFlushAll(void);
extern void cachePrepareToFlush(Buffer_s *buffer);
extern void cacheMarkDirty(Buffer_s *buffer);
extern void cacheRelease(Buffer_s *buffer);
extern void cacheReleaseToss(Buffer_s *buffer);
extern void cacheSignalRelease(Buffer_s *buffer);
extern void cacheSignalReleaseToss(Buffer_s *buffer);
extern void cacheFlush(Buffer_s *buffer);
extern BOOL cacheUnpinned(Buffer_s *buffer);
extern void cacheUnpin(Buffer_s *buffer);
extern void cacheFlushMyCache(
MyCache_s *mycache);
extern void cacheFlushMyCacheBufs(
MyCache_s *mycache);
extern void asyncCacheAllocBuffer(
Asyncio_s *asyncio,
voidfunc_t action,
AgentSignalFunc_t signal );
extern void asyncCacheAllocBufferForUserData(
Asyncio_s *asyncio,
voidfunc_t action,
AgentSignalFunc_t signal );
extern Buffer_s *cacheAllocBuffer(
MyCache_s *mycache,
Blknum_t fileBlk,
Blknum_t volBlk,
AgentSignalFunc_t signal,
NINT mode );
extern Buffer_s *cacheAllocBufferForUserData(
MyCache_s *mycache,
Blknum_t fileBlk,
Blknum_t volBlk,
AgentSignalFunc_t signal,
NINT mode );
extern Buffer_s *cacheAllocBufferForCopy(
MyCache_s *mycache,
Blknum_t fileBlk,
Blknum_t volBlk,
AgentSignalFunc_t signal,
BOOL userBuffer,
NINT mode );
extern Buffer_s *cacheFind (
MyCache_s *mycache,
Blknum_t fileBlk);
extern NINT isCached(
Asyncio_s *asyncio,
voidfunc_t action);
extern Buffer_s *cacheLookup(
MyCache_s *mycache,
Blknum_t fileBlk,
NINT mode);
extern Buffer_s *fastCache(
MyCache_s *mycache,
Blknum_t fileBlk,
NINT mode);
extern Buffer_s *fastReadCache(
MyCache_s *mycache,
Blknum_t fileBlk);
#if 0
extern Buffer_s *fastUpdateCache(
MyCache_s *mycache,
Blknum_t fileBlk);
#endif
extern void cacheTossAll(
MyCache_s *mycache);
extern void cacheToss(
Buffer_s *buffer);
extern void cacheTossIfThere(
MyCache_s *mycache,
Blknum_t fileBlk);
extern void cacheTruncateMyCache(
MyCache_s *mycache,
Blknum_t truncAt,
Blkcnt_t count);
extern void cacheFlushAndTossMyCacheUserData(
MyCache_s *mycache);
#if 0
extern void cacheMoveMyCacheBufList(
MyCache_s *dstMycache,
MyCache_s *srcMycache);
#endif
extern Buffer_s *cacheAllocSlab(
MyCache_s *mycache,
AgentSignalFunc_t signal);
extern Buffer_s *cacheGrabSlab(MyCache_s *mycache);
extern void cacheReleaseSlab(Buffer_s *buffer);
extern Buffer_s *cacheTakeBuffer(void);
extern void cacheGiveBuffer(Buffer_s *buffer);
/*
* Removes a buffer from the cache for a beast
*/
#define MYCACHE_RMV(_buf) \
{ \
if (QMEMBER( &((_buf)->mycacheLink))) \
{ \
DQ_RMV(_buf, mycacheLink); \
} \
}
#define NO_BONDS(_d) (((_d)->numLeft == 0) && DQ_EMPTY( &((_d)->flushList)))
#define HAVE_BONDS(_d) (((_d)->numLeft != 0) || DQ_NOT_EMPTY( &((_d)->flushList)))
#define NO_SIGNALS(_d) (STK_EMPTY((_d)->signalList))
extern void initAgent(
Agent_s *agent,
AgentSignalFunc_t signal,
char *name);
extern void LB_defaultSignal(Agent_s *agent);
extern void LB_defaultFlush(Agent_s *agent);
extern void LB_defaultFlushWait(Agent_s *agent);
extern void LB_lazyFlush(Agent_s *agent);
extern void LB_continueFlush(FsmLite_s *fsm);
/* These macros should be used in an inner flush loop where we want to setup
* binds to dirty objects and immediatly call "defaultFlush" on the outer
* object. This prevents the signal propogation until the outer default flush
* is called */
/* on 7/24/97 Paul and Neal decided these were no longer necessary and were
* probably causing us problems because , they were changed to NULL macros */
#define STOP_SIGNAL_PROPAGATION(_agent) ((void)0)
#define START_SIGNAL_PROPAGATION(_agent) ((void)0)
/*Original versions */
//#define STOP_SIGNAL_PROPAGATION(_agent) (++(_agent)->numLeft)
//#define START_SIGNAL_PROPAGATION(_agent) (--(_agent)->numLeft)
/* this was a new version of this macro created on 7/24/97 because we found
* a case where we lost a signal. We thought it might be because we decremented
* the count and didn't send the signal if it went to zero (which could happen
* if someone else were already flushing the object. We pondered this new
* version and then decided we didn't need any of this stuff and took it all out */
/*
//#define START_SIGNAL_PROPAGATION(_agent) \
// { \
// Agent_s *agent = (_agent); \
// \
// zASSERT(agent->numLeft > 0); \
// agent->numLeft--; \
// if (NO_BONDS(agent) \
// && (agent->state & AGENT_FLUSHING) \
// && (agent->state & AGENT_AWAIT_SIGNALS)) \
// { \
// agent->state &= ~AGENT_AWAIT_SIGNALS; \
// agent->signal(agent); \
// } \
// }
*/
/**
* NSS_COPY_ON_XLATCH is used to disable the code that copies
* cache buffers if someone wishes to XLATCH the cache buffer
* when the buffer is being flushed to disk.
*
*/
#define NSS_COPY_ON_XLATCH ENABLE
//#define NSS_COPY_ON_XLATCH DISABLE
#if NSS_COPY_ON_XLATCH IS_ENABLED
extern BOOL gNSSCopyOnXLatch;
#endif
/*-------------------------------------------------------------------------
* Macros and function prototypes for manipulating bonds
* If using BOND_FSM_GET, you must call initBind to initialize
* the bond. The function _action is called with fsm and bond:
* _action(fsm, bond);
*-------------------------------------------------------------------------*/
extern ControlStore_s BondControl;
#define BOND_FSM_GET(_fsm, _action) \
CONTROL_fsmGet( &BondControl, (_fsm), (_action))
#define GET_BOND() ((Bond_s *)CONTROL_get( &BondControl))
#define SETUP_BOND(_bond, _toSignal, _toFlush) \
{ \
(_bond)->toSignal = (_toSignal); \
(_bond)->toFlush = (_toFlush); \
STK_PUSH((_toFlush)->signalList, (_bond), signalLink); \
DQ_ENQ( &(_toSignal)->flushList, (_bond), flushLink); \
}
#if NSS_DEBUG IS_ENABLED
#define FREE_UNUSED_BOND(_bond) \
((_bond)->toSignal = NULL, \
(_bond)->toFlush = NULL, \
LB_freeBond(_bond))
#else
#define FREE_UNUSED_BOND(_bond) \
(LB_freeBond(_bond))
#endif
void LB_initBind(Bond_s *bond, Agent_s *toSignal, Agent_s *toFlush);
void LB_bind(Agent_s *toSignal, Agent_s *toFlush);
void LB_freeBond(Bond_s *bond);
/*-------------------------------------------------------------------------
* Macros and function prototypes for manipulating asyncio structures
* The function _action is called with fsm and asyncio:
* _action(fsm, asyncio);
*-------------------------------------------------------------------------*/
extern ControlStore_s AsyncioControl;
extern ControlStore_s AsyncioControlRA;
#define ASYNCIO_FSM_GET(_fsm, _action) \
CONTROL_fsmGet( &AsyncioControl, (_fsm), (_action));
void LB_freeAsyncio(Asyncio_s *asyncio);
void LB_freeAsyncioRA(Asyncio_s *asyncio);
Asyncio_s *LB_getAsyncio(void);
Asyncio_s *LB_getAsyncioNoWait(void);
Asyncio_s *LB_getAsyncioNoWaitRA(void);
void WORK_Queue(FsmLite_s *fsm, voidfunc_t action, ADDR parameter);
void WORK_Schedule(FsmLite_s *fsm, voidfunc_t action, ADDR parameter);
void WORK_Schedule_HIGH(FsmLite_s *fsm, voidfunc_t action, ADDR parameter);
void WORK_Schedule_LOW(FsmLite_s *fsm, voidfunc_t action, ADDR parameter);
void WORK_WaitForPending(void);
extern void retBuffer_s(Buffer_s *buf);
void CACHE_LinuxStatsUpdate( BOOL user, NINT mode, BOOL missLinux );
#ifdef __cplusplus
}
#endif
#endif