From d9fd616fdad7c352f3aeb2bc186107bcf7d69495 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Tue, 16 Jun 2026 12:50:53 +0000 Subject: [PATCH] 0611 nwnss: import COMN oplock runtime --- include/nwnss/include/pssConfig.h | 380 ++++++++++++ src/nwnss/CMakeLists.txt | 1 + src/nwnss/comn/common/comnOpLock.c | 637 +++++++++++++++++++++ src/nwnss/comn/common/temporaryComnStubs.c | 15 - 4 files changed, 1018 insertions(+), 15 deletions(-) create mode 100644 include/nwnss/include/pssConfig.h create mode 100644 src/nwnss/comn/common/comnOpLock.c diff --git a/include/nwnss/include/pssConfig.h b/include/nwnss/include/pssConfig.h new file mode 100644 index 0000000..24ff4b7 --- /dev/null +++ b/include/nwnss/include/pssConfig.h @@ -0,0 +1,380 @@ +/**************************************************************************** + | + | (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-06-07 02:25:28 +0530 (Thu, 07 Jun 2007) $ + | + | $RCSfile$ + | $Revision: 2044 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Define configuration values for the Z file system + | + | 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 _PSSCONFIG_H_ +#define _PSSCONFIG_H_ + +#ifndef _OMNI_H_ +#include +#endif + +#include "hmc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern NINT WorkWaitingCount; +extern NINT WorkHighWaitingCount; + +#define CACHE_BALANCE_TIMER_SECS 30 +#define MIN_OS_FREE_CACHE_BUFS 256 +#define DEFAULT_NUM_BUFFERS_PER_SESSION 1024 + +#define PERCENT_OF_OS_BUFS(_num) (((_num)*Config.cache.percentOfOSFree)/100) +#define BALANCE_CACHE_MIN 16 + +#define MAX_PERCENT_FOR_USER_PAGES 50 + +#if defined(__i386__) +#define DEFAULT_HMC_CACHE_TYPE HMC_CT_PRIVATE +#endif +#if defined(__x86_64__) +#define DEFAULT_HMC_CACHE_TYPE HMC_CT_NONE +#endif +#define DEFAULT_PRIVATE_CACHE_PAGES 1 /* Calculated in HMC_Startup */ + + + +/** Set Maximum value to zero if there is no Maximum limit for the variable **/ +/** Set Minimum value to zero if the variable can be set to zero **/ + +/* Range definitions*/ +//#define MIN_NUM_BUFFERS 8 /* See debug area */ +#define MAX_NUM_BUFFERS 1048576 /* Upto 4 GB of memory */ + +#define MIN_NUM_ASYNCIOS 4 +#define MAX_NUM_ASYNCIOS 65536 + +#define MIN_NUM_BONDS (2 * MIN_NUM_BUFFERS) +#define MAX_NUM_BONDS (2 * MAX_NUM_BUFFERS) + +//#define MIN_CACHE_HASH_SHIFT 8 +//#define MAX_CACHE_HASH_SHIFT 20 + +#define MIN_NOT_IN_USE_BEASTS 16 +#define MAX_NOT_IN_USE_BEASTS 1000000 +#define MIN_BEASTS_TO_RETURN 16 /* Always return at least this many */ + +#define MIN_BEAST_HASH_SHIFT 8 +#define MAX_BEAST_HASH_SHIFT 25 + +#define MIN_SIZE_MAILBOX 256 +#define MAX_SIZE_MAILBOX 65536 + +#define MIN_SEC 1 +#define MAX_SEC 3600 + +#define MIN_WORK_LIMIT 5 +#define MAX_WORK_LIMIT 100 + +#define MIN_NUM_XACTIONS 4 +#define MAX_NUM_XACTIONS 65536 + +#define MIN_NUM_XDELETES 4 +#define MAX_NUM_XDELETES 65536 + +#define MIN_STORAGE_ALARM_THRESHOLD 0 +#define MAX_STORAGE_ALARM_THRESHOLD 1000000 + +#define MIN_STORAGE_RESET_THRESHOLD 0 +#define MAX_STORAGE_RESET_THRESHOLD 1000000 + +#define DEFAULT_BEAST_PERCENT_MEM 45 + +#define DEFAULT_BEAST_BALANCE_SEC 1 + +#define MIN_ALLOC_AHEAD_WRITE 0 +#define DEFAULT_ALLOC_AHEAD_WRITE 0 // On linux most applications on + // server and ncp and probably cifs + // do larger writes (not network + // packet size writes). So we get + // better performance without + // allocahead. +#define MAX_ALLOC_AHEAD_WRITE 63 + + +#if NSS_DEBUG IS_ENABLED + /* + * DEBUG values + */ +#define PERCENT_OS_FREE_CACHE 99 +#define PRERESERVE_FOR_BEAST_FLUSH 64 +#define CACHE_HYSTERESIS 16 /* Have to have at least this many OS + * buffers that we can take before we + * take any. + */ +#define MIN_NUM_BUFFERS (CACHE_HYSTERESIS + PRERESERVE_FOR_BEAST_FLUSH) + +#define DEFAULT_NUM_BONDS 5000 /*(2 * DEFAULT_NUM_BUFFERS)*/ +#define DEFAULT_NUM_BUFFERS 512 +#define DEFAULT_NUM_ASYNCIOS 2048 +#define DEFAULT_NUM_DELAYED_BEASTS 40 +//#define DEFAULT_CACHE_HASH_SHIFT 10 +#define DEFAULT_NOT_IN_USE_BEASTS 100000 +//#define DEFAULT_BEAST_HASH_SHIFT 12 +#define DEFAULT_SIZE_MAILBOX 512 +#define DEFAULT_SEC_BEAST 10 +#define DEFAULT_SEC_XACTION 20 +#define DEFAULT_SEC_CHKPT 30 +#define DEFAULT_SEC_OPLOCKWAIT 30 +#define DEFAULT_WORK_LIMIT 30 +#define DEFAULT_NUM_XACTIONS 50 +#define DEFAULT_NUM_XDELETES 10 +#define DEFAULT_STORAGE_ALARM_THRESHOLD 1 /* in kbytes */ +#define DEFAULT_STORAGE_RESET_THRESHOLD 2 /* in kbytes */ +#define DEFAULT_STORAGE_SEND_ALERT 1 /* boolean */ +#else + /* + * PRODUCTION values + */ +#define PERCENT_OS_FREE_CACHE 85 +#define PRERESERVE_FOR_BEAST_FLUSH 128 +#define CACHE_HYSTERESIS 256 /* Have to have at least this many OS + * buffers that we can take before we + * take any. + */ +#define MIN_NUM_BUFFERS (CACHE_HYSTERESIS + PRERESERVE_FOR_BEAST_FLUSH) + +#define DEFAULT_NUM_BONDS 5000 /*(2 * DEFAULT_NUM_BUFFERS)*/ +#define DEFAULT_NUM_BUFFERS 512 +#define DEFAULT_NUM_ASYNCIOS 2048 +#define DEFAULT_NUM_DELAYED_BEASTS 40 +//#define DEFAULT_CACHE_HASH_SHIFT 13 +#define DEFAULT_NOT_IN_USE_BEASTS 100000 +//#define DEFAULT_BEAST_HASH_SHIFT 16 +#define DEFAULT_SIZE_MAILBOX 512 +#define DEFAULT_SEC_BEAST 10 +#define DEFAULT_SEC_XACTION 20 +#define DEFAULT_SEC_CHKPT 30 +#define DEFAULT_SEC_OPLOCKWAIT 30 +#define DEFAULT_WORK_LIMIT 50 +#define DEFAULT_NUM_XACTIONS 5000 +#define DEFAULT_NUM_XDELETES 1000 +#define DEFAULT_STORAGE_ALARM_THRESHOLD 10 /* in megabytes */ +#define DEFAULT_STORAGE_RESET_THRESHOLD 15 /* in megabytes */ +#define DEFAULT_STORAGE_SEND_ALERT 1 /* boolean */ +#endif + +#define DEFAULT_SEC_JOURNAL_GROUP_WRITE 1 +#define DEFAULT_SEC_METADATA_GROUP_WRITE 40 +#define DEFAULT_SEC_USER_DATA_GROUP_WRITE 3 +#define DEFAULT_METADATA_GROUP_WRITE_LIMIT 20000 /* Really a limit target */ + +#define DEFAULT_CHECKER TRUE +#define DEFAULT_FORCE_CHECKER FALSE +#define DEFAULT_WORK_DELAY_CNT 100 +#define DEFAULT_MSEC_WORK_WAIT 100 + +#define DEFAULT_MAX_WORK_WAITING 1000 +#define DEFAULT_MAX_HIGH_WORK_WAITING 50 + +#define DEFAULT_LV_PURGE_DELAY_AFTER_DELETE_SECONDS (60 * 60 * 24 * 4) /* 4 days (was 2 days, but increased so to stay around over LONG weekend)*/ +#define DEFAULT_LV_PURGE_DELAY_AFTER_LOAD_SECONDS (60 * 60 * 2) /* 2 hour */ +#define DEFAULT_LV_PURGE_DELAY_AFTER_LAST_ENTRY_SECONDS (60 * 15) /* 15 minutes */ + +#if zLINUX +#define DEFAULT_SECURITY_EQUIV_UPDATER TRUE +#define DEFAULT_FORCE_SECURITY_EQUIV_UPDATER FALSE +#define DEFAULT_SECURITY_EQUIV_UPDATER_SECONDS (((60 * 60) * 2) + 37) /* 2 hours and 37 seconds */ +#define DEFAULT_SECURITY_EQUIV_UPDATER_CHANGED FALSE +#endif + +/* min/max values for the high/low watermarks used to control purge limits */ +#define zMAX_HIGHWATERMARK 100 +#define zMIN_HIGHWATERMARK 2 +#define zMAX_LOWWATERMARK 98 +#define zMIN_LOWWATERMARK 0 + +typedef struct Config_s +{ + struct Cache_s + { + NINT numBuffers; + NINT numBonds; + NINT numAsyncios; +// NINT hashShift; + NINT hashSize; + NINT hashMask; + + BOOL usePercentMemory; + NINT percentOfOSFree; + NINT balanceTimerSecs; + NINT minOSFree; + NINT numPagesAllocated; + NINT maxNumBuffersToAddPerBalance; + NINT userPages; /* number of pages used for user data */ + NINT percentUserPages; /* percentage of total pages for user */ + NINT hmcCacheType; /* HMC_CT_LINUX, HMC_CT_NONE, or + HMC_CT_PRIVATE. Needed on servers with limited low + memory, but lots of high memory. In which case, + NSS will use high memory as a secondary cache for + its meta-data blocks unless user turns off. */ + NINT privateHashSize; + NINT privateHashMask; + NINT privateCachePageBuffers; /* Number of page buffers that are + currently in the private cache. */ + NINT privateCachePages; /* Number of pages that are currently + attached to our page buffers. */ + NINT privateCacheSizeRequest; /* For HMC_CT_PRIVATE. Number of + pages buffers to have in the private cache. The + actual number of page buffers that we have is + in privateCachePageBuffers. */ + BOOL privateCacheSizeRequestStartup; /* Indicates that user + set privateCacheSizeRequest at startup time. */ + NINT metadataBlocksReadyForGroupWriteLimit; /* Limits the number + of metadata blocks that are on the metadata + group write list. This limits the amount of + time needed to play the journal after a crash. */ + NINT metadataBlocksReadyForGroupWrite; /* Current count of + metadata blocks that are on the metadata group + write list. */ + } cache; + struct Os_s + { + NINT sizeMailbox; + NINT workLimit; + NINT workDelayCnt; + } os; + struct Bst_s + { + NINT notInUseMax; /* Max beasts allowed to be not in use */ + NINT percentMemory; /* Max % memory to be used by beasts */ + NINT balanceTimerSecs; /* Balance beasts with memory */ +// NINT hashShift; + NINT hashSize; +// NINT hashMask; + NINT notInUseLimit; /* Current limit for not in use beasts */ + NINT total; /* Total number of beasts in memory */ + NINT notInUse; /* Number of closed beasts not in use */ + SNINT remainingLimit; /* Remaining limit of beasts */ + } bst; + struct Sec_s + { + NINT beast; + NINT xaction; + NINT chkpt; + NINT opLockWait; + NINT journalGroupWriteTime; + NINT metadataGroupWriteTime; + NINT userDataGroupWriteTime; + } sec; + struct Msec_s + { + NINT workWait; + } msec_s; + struct Tick_s + { + NINT beast; + NINT xaction; + NINT chkpt; + NINT opLockWait; + } tick; + struct NumWork_s + { + NINT waiting; + NINT waitingHigh; + } work; + struct Xact_s + { + NINT numDelayed; + } xact; + struct Zfs_s + { + NINT numXactions; + NINT numXdeletes; + } zfs; + struct Storage + { + NINT alarmThreshold; + NINT resetThreshold; + BOOL sendAlert; + NINT allocAhead; + BOOL checker; /* TRUE if the background checker is to be run */ + BOOL forceChecker; /* TRUE if the background checker is to be forced to run */ + } Storage; + struct LV_s + { + NINT PurgeDelayAfterDeleteSeconds; /* Number of seconds that + a volume is non-purgeable. */ + NINT PurgeDelayAfterLoadSeconds; /* Number of seconds that + a volume will not be purged in + after NSS loads. Used to give the + ADMIN some time to change state of + a deleted volume after load. */ + NINT PurgeDelayAfterLastEntrySeconds; /* Number of seconds that + a volume is non-purgeable after + its last entry into purgeable state. + E.G. if a LV is paused then + un-paused after its normal purge + time then it will not be purgeable + for the number of seconds indicated + by this element. */ + } lv; +#if zLINUX + struct SecEquiv_s + { + BOOL updater; /* TRUE if the security equivalence + * background updater is to be run */ + BOOL forceUpdater; /* TRUE if the security equivalence + * background updater is to be + * forced to be run */ + NINT updaterInterval; /* Number of seconds that we delay + * after finishing a security + * equivalence update and before + * starting a new one.*/ + BOOL intervalChanged; /* TRUE if the security equivalence + * background interval was changed */ + } SecEquiv; +#endif +} Config_s; + +extern Config_s Config; + +void configStartup(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/nwnss/CMakeLists.txt b/src/nwnss/CMakeLists.txt index 7d986e9..942dad5 100644 --- a/src/nwnss/CMakeLists.txt +++ b/src/nwnss/CMakeLists.txt @@ -129,6 +129,7 @@ add_library(nwnss SHARED comn/common/fsmsg.c comn/common/fileHandle.c comn/common/csaLease.c + comn/common/comnOpLock.c comn/common/nameScan.c comn/namespace/nameSpace.c comn/namespace/dosNSpace.c diff --git a/src/nwnss/comn/common/comnOpLock.c b/src/nwnss/comn/common/comnOpLock.c new file mode 100644 index 0000000..fb78c99 --- /dev/null +++ b/src/nwnss/comn/common/comnOpLock.c @@ -0,0 +1,637 @@ +/**************************************************************************** + | + | (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) module + | + |--------------------------------------------------------------------------- + | + | $Author: blarsen $ + | $Date: 2006-01-21 04:09:53 +0530 (Sat, 21 Jan 2006) $ + | + | $RCSfile$ + | $Revision: 1315 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Define the Common side of OpLocks. + | + +-------------------------------------------------------------------------*/ + +#include + +#include +#include +#include "msgGen.h" +#include "xError.h" +#include "pssConfig.h" +#include "fileHandle.h" +#include "comnBeasts.h" +#include "opLock.h" +#include "pssStartup.h" +#include "comnPublics.h" +#include "schedule.h" +extern STATUS snoozeSec(DQhead_t *list, NINT seconds); +extern void roust(DQhead_t *list, STATUS status); + +#ifndef __linux__ // LINUX_NetWareAlerts +extern NetWareAlertStructure OpLockTimeoutAlert; + +GROUP_EVENT evOpLockTimeout = +{ + GEventcbID, VTLong, 0, LocksSubjects + 10, 0, 0, + nmOpLockTimeout, &OpLockTimeoutAlert, 0, 0 +}; + +NetWareAlertStructure OpLockTimeoutAlert = { + &evOpLockTimeout, + QAlert320Mask, + 0, + NOTIFY_ERROR_LOG_BIT | NOTIFY_CONSOLE_BIT, + ALERT_ID(ALERT_OS, nmOpLockTimeout), + LOCUS_LOCKS, + CLASS_STATION_FAILURE, + SEVERITY_OPERATION_ABORTED, + NULL, NULL, 0, + InxMSG("Station %d (task %d) timed out waiting for an op-lock on file %s held by station %d.", 592) +}; +#endif + +BOOL OpLockVerbose = FALSE; // TRUE; +OpLockInst_s OpLockInst; + + +OpLockControl_s *getOpLockControl (File_s *file) +{ + OpLockControl_s *opLockControl; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH( &file->FILEbeastLatch); + + opLockControl = file->opLockControl; + if (opLockControl == NULL) + { + opLockControl = zalloc(sizeof(OpLockControl_s)); + if (opLockControl == NULL) + { + return NULL; + } + file->opLockControl = opLockControl; + opLockControl->opFile = file; + DQ_INIT( &opLockControl->opLockWaiters); + DQ_INIT( &opLockControl->opLocks); + opLockControl->opState = OPLOCK_IDLE; + opLockControl->opHasPSA = FALSE; + } + return opLockControl; +} + +void OPLOCK_roust (OpLockControl_s *opLockControl) +{ + if (DQ_EMPTY( &opLockControl->opLocks)) + { + opLockControl->opState = OPLOCK_IDLE; + roust( &opLockControl->opLockWaiters, zOK); + } +} + +OpLock_s *OPLOCK_AllocExclusive ( + FileHandle_s *fh, + statusfunc_t opCallback) +{ + File_s *file = fh->file; + OpLock_s *opLock; + OpLockControl_s *opLockControl; + + ASSERT_MPKNSS_LOCK(); + zASSERT(fh->opLock == NULL); + ASSERT_XLATCH( &file->FILEbeastLatch); + + if (file->FILEopenCount != 1) + { + return NULL; + } + opLockControl = getOpLockControl(file); + if (opLockControl == NULL) + { + return NULL; + } + opLock = zalloc(sizeof(OpLock_s)); + if (opLock == NULL) + { + return NULL; + } + switch (opLockControl->opState) + { + case OPLOCK_IDLE: + break; + case OPLOCK_EXCLUSIVE: + case OPLOCK_BREAKING_EXCLUSIVE: + case OPLOCK_SHARED: + case OPLOCK_BREAKING_SHARED: + free(opLock); + return NULL; + } + opLockControl->opState = OPLOCK_EXCLUSIVE; + opLock->opCallback = opCallback; + opLock->fileHandle = fh; + opLock->control = opLockControl; + DQ_ENQ( &opLockControl->opLocks, opLock, opLink); + fh->opLock = opLock; + + OPLOCK(allocExclusive); + return opLock; +} + +OpLock_s *OPLOCK_AllocShared ( + FileHandle_s *fh, + statusfunc_t opCallback) +{ + File_s *file = fh->file; + OpLock_s *opLock; + OpLockControl_s *opLockControl; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH( &file->FILEbeastLatch); + + opLockControl = getOpLockControl(file); + if (opLockControl == NULL) + { + return NULL; + } + opLock = zalloc(sizeof(OpLock_s)); + if (opLock == NULL) + { + return NULL; + } + switch (opLockControl->opState) + { + case OPLOCK_IDLE: + case OPLOCK_SHARED: + break; + case OPLOCK_EXCLUSIVE: + case OPLOCK_BREAKING_EXCLUSIVE: + case OPLOCK_BREAKING_SHARED: + free(opLock); + return NULL; + } + opLockControl->opState = OPLOCK_SHARED; + opLock->opCallback = opCallback; + opLock->fileHandle = fh; + opLock->control = opLockControl; + DQ_ENQ( &opLockControl->opLocks, opLock, opLink); + fh->opLock = opLock; + if (fh->grantedRights & zRR_PSA_CACHE) + { + opLockControl->opHasPSA = TRUE; + } + OPLOCK(allocShared); + return opLock; +} + +void OPLOCK_Free (OpLock_s *opLock) +{ + FileHandle_s *fh; + OpLockControl_s *opLockControl; + + ASSERT_MPKNSS_LOCK(); + if (opLock == NULL) + { + return; + } + OPLOCK(free); + + fh = opLock->fileHandle; + ASSERT_XLATCH( &fh->file->FILEbeastLatch); + fh->opLock = NULL; + + opLock->opCallback(OPLOCK_CLEAR, NULL, opLock); + + zASSERT(!QMEMBER( &opLock->tickle)); + + opLockControl = opLock->control; + + if (QMEMBER( &opLock->opLink)) + { + DQ_RMV(opLock, opLink); + } + free(opLock); + switch (opLockControl->opState) + { + case OPLOCK_IDLE: + break; + case OPLOCK_EXCLUSIVE: // No one should be snoozing + OPLOCK_roust(opLockControl); + break; + case OPLOCK_SHARED: + break; + case OPLOCK_BREAKING_EXCLUSIVE: + OPLOCK_roust(opLockControl); + break; + case OPLOCK_BREAKING_SHARED: + break; + } + if (DQ_EMPTY( &opLockControl->opLocks)) + { + opLockControl->opState = OPLOCK_IDLE; + } +} + +void OPLOCK_TimeOutAlert ( + GeneralMsg_s *genMsg, + File_s *file, + LONG ownerStation) +{ + typedef struct Stack_s { + char name[zMAX_COMPONENT_NAME]; + unicode_t uniName[zMAX_COMPONENT_NAME]; + } Stack_s; + STATUS status; + + STACK_ALLOC(); + + if (COMN_GetNameFromBeast(genMsg, file,// cnt zFNU_FIRST_PARENT, + zNSPACE_LONG, zMAX_COMPONENT_NAME, + aStack->uniName, NULL) == zOK) + { + status = LB_UnicodeToByte(NSS_UNI_CONVERSION_RAW, aStack->name, + zMAX_COMPONENT_NAME, aStack->uniName, NULL); + if (status != zOK) + { + strcpy(aStack->name, ""); + } + } + else + { + ClearErrno(genMsg); + strcpy(aStack->name, ""); + } +#ifndef __linux__ // LINUX_NetWareAlerts + ZOS_NetWareAlert((CMN_ModuleHandle, &OpLockTimeoutAlert, 4, + genMsg->pssConn.id, genMsg->taskID, + aStack->name, ownerStation)); +#endif + STACK_FREE(); +} + + /* + * Assumptions: + * 1. COMN_BreakOpLock or OPLOCK_BreakExclusive + * has been called and returned zERR_OPLOCK_MUST_WAIT. + * 2. The thread has released all of its latches. (This does + * not mean that someone else can't have a latch.) + * 3. The thread will reaquire the latches its needs after + * this call returns. + * 4. If you were trying to also break shared oplocks, you'll have + * to call OPLOCK_BreakShared + */ +STATUS OPLOCK_WaitForBreak ( + GeneralMsg_s *genMsg, + File_s *file) +{ + OpLockControl_s *opLockControl; + OpLock_s *opLock; + statusfunc_t callback; + DQhead_t save; + LONG ownerStation; + STATUS rc; + + ASSERT_MPKNSS_LOCK(); + + opLockControl = file->opLockControl; + if (opLockControl == NULL) + { + return zOK; + } + /* + * Need to check state + */ + switch (opLockControl->opState) + { + case OPLOCK_IDLE: + case OPLOCK_BREAKING_SHARED: + case OPLOCK_SHARED: + case OPLOCK_EXCLUSIVE: + OPLOCK_roust(opLockControl); /* Wake up anybody that might be sleeping */ + zASSERT("OpLock should be in OPLOCK_BREAKING_EXCLUSIVE"==0); + SetErrno(genMsg, zERR_INVALID_STATE); + return zFAILURE; + case OPLOCK_BREAKING_EXCLUSIVE: + break; + } + /* Notify SA that we are waiting (deadlock detection for nwSA) */ + DQ_PEEK( &opLockControl->opLocks, opLock, OpLock_s, opLink); + if (opLock == NULL) + { + opLockControl->opState = OPLOCK_IDLE; + return zOK; + } + callback = opLock->opCallback; + rc = callback(OPLOCK_WAITING, genMsg, opLock); + + OPLOCK(waitForBreak); + rc = snoozeSec( &opLockControl->opLockWaiters, Config.sec.opLockWait); + callback(OPLOCK_WAIT_OVER, genMsg, NULL); + if (rc == zOK) + { + goto exit; + } + if (rc != zERR_TIMEOUT) + { + goto exit; + } + OPLOCK(timedOut); + /* + * Give the SA a chance to break the oplock + */ + rc = zOK; + ownerStation = -1; + DQ_INIT( &save); + for (;;) + { + DQ_DEQ( &opLockControl->opLocks, opLock, OpLock_s, opLink); + if (opLock == NULL) + { + break; + } + DQ_ENQ( &save, opLock, opLink); + if (opLock->fileHandle) + { + ownerStation = opLock->fileHandle->connID; + } + rc = opLock->opCallback(OPLOCK_TIMEOUT, genMsg, opLock); + ASSERT_MPKNSS_LOCK(); + if (rc != zOK) + { + break; + } + } + DQ_APPEND( &opLockControl->opLocks, &save); + if (rc == zOK) + { + goto exit; + } + if (rc == zERR_TIMEOUT) + { + OPLOCK_TimeOutAlert(genMsg, file, ownerStation); + } +exit: + if (rc == zOK) + { + return rc; + } + SetErrno(genMsg, zERR_OPLOCK_COLLISION); + return zFAILURE; +} + +STATUS OPLOCK_BreakExclusive ( + GeneralMsg_s *genMsg, /* Has the connection ID and task */ + File_s *file, + BOOL wait) +{ + OpLockControl_s *opLockControl = file->opLockControl; + statusfunc_t callback; + OpLock_s *opLock; + STATUS rc; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH( &file->FILEbeastLatch); + /* + * See if we have to break any opLocks + */ + if (opLockControl == NULL) + { + return zOK; + } + switch (opLockControl->opState) + { + case OPLOCK_IDLE: + return zOK; + + case OPLOCK_EXCLUSIVE: + DQ_PEEK( &opLockControl->opLocks, opLock, OpLock_s, opLink); + if (opLock == NULL) + { + opLockControl->opState = OPLOCK_IDLE; + return zOK; + } + callback = opLock->opCallback; + rc = callback(OPLOCK_BREAK, genMsg, opLock); + ASSERT_MPKNSS_LOCK(); + if (rc != zOK) + { + if (GetErrno(genMsg) == zERR_IGNORE_OPLOCK_BREAK) + { + ClearErrno(genMsg); + return zOK; + } + return rc; + } + opLockControl->opState = OPLOCK_BREAKING_EXCLUSIVE; + OPLOCK(breakExclusive); + if (!wait) + { + SetErrno(genMsg, zERR_OPLOCK_MUST_WAIT); + return zFAILURE; + } + + UNX_LATCH( &file->FILEbeastLatch); + rc = OPLOCK_WaitForBreak(genMsg, file); + X_LATCH( &file->FILEbeastLatch); + return rc; + + case OPLOCK_BREAKING_EXCLUSIVE: + if (!wait) + { + SetErrno(genMsg, zERR_OPLOCK_MUST_WAIT); + return zFAILURE; + } + /* + * Do we need oplock deadlock detection for this case? + */ + UNX_LATCH( &file->FILEbeastLatch); + rc = OPLOCK_WaitForBreak(genMsg, file); + X_LATCH( &file->FILEbeastLatch); + return rc; + + case OPLOCK_SHARED: + case OPLOCK_BREAKING_SHARED: + return zOK; + + default: + zASSERT("Bad oplock state" == 0); + SetErrno(genMsg, zERR_INVALID_STATE); + return zFAILURE; + } +} + +STATUS OPLOCK_BreakShared (File_s *file) +{ + OpLockControl_s *opLockControl = file->opLockControl; + OpLock_s *opLock; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH( &file->FILEbeastLatch); + /* + * See if we have to break any opLocks + */ + if (opLockControl == NULL) + { + return zOK; + } + if (opLockControl->opState != OPLOCK_SHARED) + { + return zOK; + } + /* + * Break the shared op-locks + */ + opLockControl->opState = OPLOCK_BREAKING_SHARED; + for (;;) + { + DQ_DEQ( &opLockControl->opLocks, opLock, OpLock_s, opLink); + if (opLock == NULL) + { + break; + } + OPLOCK(breakShared); + opLock->opCallback(OPLOCK_BREAK, NULL, opLock); + /* + * We are ignoring callbacks that failed. It is + * their problem, not ours. + */ + ASSERT_MPKNSS_LOCK(); + } + opLockControl->opState = OPLOCK_IDLE; + return zOK; +} + + /* + * Break shared oplocks setup by PSA. PSA has to be treated + * different because it does not close shared oplocks immediately + * after it is done with them. + */ +STATUS OPLOCK_BreakPSA (File_s *file) +{ + OpLockControl_s *opLockControl = file->opLockControl; + OpLock_s *opLock; + OpLock_s *psaOpLock; + DQhead_t psaHead; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH( &file->FILEbeastLatch); + /* + * See if we have to break any opLocks + */ + if (opLockControl == NULL) + { + return zOK; + } + if (opLockControl->opState != OPLOCK_SHARED) + { + return zOK; + } + if (!opLockControl->opHasPSA) + { + return zOK; + } + /* + * Break the PSA shared op-locks + */ + DQ_INIT( &psaHead); + DQ_FOREACH( &opLockControl->opLocks, opLock, OpLock_s, opLink) + { + if (!(opLock->fileHandle->grantedRights & zRR_PSA_CACHE)) + { + continue; + } + psaOpLock = opLock; + opLock = OPREV(psaOpLock, OpLock_s, opLink); + DQ_RMV(psaOpLock, opLink); + DQ_ENQ( &psaHead, psaOpLock, opLink); + } + opLockControl->opHasPSA = FALSE; + if (DQ_EMPTY( &opLockControl->opLocks)) + { + opLockControl->opState = OPLOCK_IDLE; + } + for (;;) + { + DQ_DEQ( &psaHead, opLock, OpLock_s, opLink); + if (opLock == NULL) + { + break; + } + OPLOCK(breakShared); + opLock->opCallback(OPLOCK_BREAK, NULL, opLock); + ASSERT_MPKNSS_LOCK(); + } + return zOK; +} + +STATUS OPLOCK_Break ( + GeneralMsg_s *genMsg, /* Brings along the connection ID */ + File_s *file, + BOOL wait) +{ + STATUS rc; + + ASSERT_MPKNSS_LOCK(); + + OPLOCK(breakAll); + rc = OPLOCK_BreakExclusive(genMsg, file, wait); + if (rc != zOK) + { + return rc; + } + return OPLOCK_BreakShared(file); +} + +void OPLOCK_MakeShared (OpLock_s *opLock) +{ + OpLockControl_s *opLockControl = opLock->control; + + ASSERT_MPKNSS_LOCK(); + + OPLOCK(makeShared); + + if (opLockControl) + { + opLockControl->opState = OPLOCK_SHARED; + roust( &opLockControl->opLockWaiters, zOK); + } +} + +void OPLOCK_BreakFailed (OpLock_s *opLock) +{ + OpLockControl_s *opLockControl = opLock->control; + + ASSERT_MPKNSS_LOCK(); + + OPLOCK(breakFailed); + + if (opLockControl) + { + ASSERT_XLATCH( &opLockControl->opFile->FILEbeastLatch); + opLockControl->opState = OPLOCK_EXCLUSIVE; + roust( &opLockControl->opLockWaiters, zERR_OPLOCK_NOT_BROKEN); + } +} diff --git a/src/nwnss/comn/common/temporaryComnStubs.c b/src/nwnss/comn/common/temporaryComnStubs.c index ac56985..d1334e2 100644 --- a/src/nwnss/comn/common/temporaryComnStubs.c +++ b/src/nwnss/comn/common/temporaryComnStubs.c @@ -490,21 +490,6 @@ STATUS BST_flush(void *beast) return zERR_FAILURE; } -OpLock_s *OPLOCK_AllocShared(FileHandle_s *fh, statusfunc_t opCallback) -{ - (void)fh; - (void)opCallback; - return NULL; -} - -STATUS OPLOCK_BreakExclusive(GeneralMsg_s *genMsg, File_s *file, BOOL wait) -{ - (void)genMsg; - (void)file; - (void)wait; - return zERR_FAILURE; -} - void MSG_Notify(FileHandle_s *fileHandle) { (void)fileHandle;