2025-04-27 07:49:33 -04:00

449 lines
13 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++ BUILD Version: 0009 // Increment this if a change has global effects
Copyright (c) 1987-1993 Microsoft Corporation
Module Name:
smbcemid.c
Abstract:
This module defines the routines for manipulating MIDs associated with SMB's
Notes:
--*/
#include "precomp.h"
#pragma hdrstop
RXDT_DefineCategory(SMBCEMID);
#define Dbg (DEBUG_TRACE_SMBCEMID)
NTSTATUS
SmbCeAssociateExchangeWithMid(
PSMBCEDB_SERVER_ENTRY pServerEntry,
struct _SMB_EXCHANGE *pExchange)
/*++
Routine Description:
This routine associates an exchange with a MID
Arguments:
pServerEntry - the servere entry
pExchange - the Exchange instance.
Return Value:
STATUS_SUCCESS if successful, otherwise one of the following errors
Notes:
If an asynchronous mechanism to acquire MID's is to be introduced this routine
needs to be modified. Currently this routine does not return control till a
MID is acquired or the exchange is aborted/terminated.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PSMBCEDB_REQUEST_ENTRY pRequestEntry;
SMBCE_RESUMPTION_CONTEXT ResumptionContext;
SMBCEDB_SERVER_TYPE ServerType;
ServerType = SmbCeGetServerType(pServerEntry);
// Acquire the resource
SmbCeAcquireSpinLock();
// Attempt to allocate a MID only for FILE Servers. Mailslot servers do
// not require a valid MID.
if (ServerType != SMBCEDB_MAILSLOT_SERVER) {
if (pServerEntry->pMidAtlas != NULL) {
if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_INDEFINITE_DELAY_IN_RESPONSE) {
// This exchange response can be arbitrarily delayed. Ensure that
// all the available MIDS are not tied up in such exchanges.
if ((pServerEntry->pMidAtlas->NumberOfMidsInUse + 1) ==
pServerEntry->pMidAtlas->MaximumNumberOfMids) {
Status = STATUS_TOO_MANY_COMMANDS;
}
}
if (Status == STATUS_SUCCESS) {
Status = IfsMrxAssociateContextWithMid(
pServerEntry->pMidAtlas,
pExchange,
&pExchange->Mid);
}
} else {
Status = STATUS_INVALID_PARAMETER;
}
}
if (Status == STATUS_UNSUCCESSFUL) {
// Allocate a new entry and add it to the list.
pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
if (pRequestEntry != NULL) {
// Enqueue the request entry.
SmbCeInitializeResumptionContext(&ResumptionContext);
pRequestEntry->MidRequest.Type = ACQUIRE_MID_REQUEST;
pRequestEntry->MidRequest.pExchange = pExchange;
pRequestEntry->MidRequest.pResumptionContext = &ResumptionContext;
SmbCeAddRequestEntryLite(&pServerEntry->MidAssignmentRequests,pRequestEntry);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
} else if (Status == STATUS_SUCCESS) {
pExchange->SmbCeFlags |= SMBCE_EXCHANGE_MID_VALID;
}
// Release the resource
SmbCeReleaseSpinLock();
if (Status == STATUS_UNSUCCESSFUL) {
//DbgPrint("***** Thread %lx Waiting for MID Resumption Context %lx*****\n",PsGetCurrentThread(),&ResumptionContext);
SmbCeSuspend(&ResumptionContext);
Status = ResumptionContext.Status;
//DbgPrint("***** Thread %lx MID Wait Satisfied %lx *****\n",PsGetCurrentThread(),&ResumptionContext);
}
return Status;
}
struct _SMB_EXCHANGE *
SmbCeMapMidToExchange(
PSMBCEDB_SERVER_ENTRY pServerEntry,
SMB_MPX_ID Mid)
/*++
Routine Description:
This routine maps a given MID to the exchange associated with it
Arguments:
pServerEntry - the servere entry
Mid - the mid to be mapped to an Exchange.
Return Value:
a valid SMB_EXCHANGE instance if successful, otheriwse NULL.
--*/
{
PSMB_EXCHANGE pExchange;
// Acquire the resource
SmbCeAcquireSpinLock();
if (pServerEntry->pMidAtlas != NULL) {
pExchange = IfsMrxMapMidToContext(
pServerEntry->pMidAtlas,
Mid);
} else {
pExchange = NULL;
}
// Release the resource
SmbCeReleaseSpinLock();
return pExchange;
}
NTSTATUS
SmbCeDisassociateMidFromExchange(
PSMBCEDB_SERVER_ENTRY pServerEntry,
struct _SMB_EXCHANGE *pExchange)
/*++
Routine Description:
This routine disassociates an exchange from the MID
Arguments:
pServerEntry - the servere entry
pExchange - the exchange instance.
Return Value:
a valid SMB_EXCHANGE instance if successful, otheriwse NULL.
Notes:
If an asynchronous mechanism to acquire MID's is to be introduced this routine
needs to be modified. This modification will also include posting requests
for resumption of exchanges when invoked at DPC level.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SMBCEDB_SERVER_TYPE ServerType;
ServerType = SmbCeGetServerType(pServerEntry);
if ((ServerType != SMBCEDB_MAILSLOT_SERVER) &&
(pExchange->Mid != SMBCE_OPLOCK_RESPONSE_MID)) {
PVOID pContext;
PSMBCEDB_REQUEST_ENTRY pRequestEntry = NULL;
// Acquire the resource
SmbCeAcquireSpinLock();
if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
// Check if there are any pending MID assignment requests and transfer the MID
// if one exists.
pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->MidAssignmentRequests);
if (pRequestEntry != NULL) {
SmbCeRemoveRequestEntryLite(&pServerEntry->MidAssignmentRequests,pRequestEntry);
}
if (pServerEntry->pMidAtlas != NULL) {
if (pRequestEntry != NULL) {
Status = IfsMrxReassociateMid(
pServerEntry->pMidAtlas,
pExchange->Mid,
pRequestEntry->MidRequest.pExchange);
ASSERT(Status == STATUS_SUCCESS);
pRequestEntry->MidRequest.pExchange->SmbCeFlags |= SMBCE_EXCHANGE_MID_VALID;
pRequestEntry->MidRequest.pExchange->Mid = pExchange->Mid;
pRequestEntry->MidRequest.pResumptionContext->Status = STATUS_SUCCESS;
} else {
Status = IfsMrxMapAndDissociateMidFromContext(
pServerEntry->pMidAtlas,
pExchange->Mid,
&pContext);
ASSERT(pContext == pExchange);
}
} else {
Status = STATUS_INVALID_PARAMETER;
}
}
// Release the resource
SmbCeReleaseSpinLock();
if (pRequestEntry != NULL) {
// Signal the waiter for resumption
//DbgPrint("***** Satisfying wait on MID Resumption Context %lx*****\n",pRequestEntry->MidRequest.pResumptionContext);
SmbCeResume(pRequestEntry->MidRequest.pResumptionContext);
SmbCeTearDownRequestEntry(pRequestEntry);
}
}
pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_MID_VALID;
return Status;
}
struct _SMB_EXCHANGE *
SmbCeGetExchangeAssociatedWithBuffer(
PSMBCEDB_SERVER_ENTRY pServerEntry,
PVOID pBuffer)
/*++
Routine Description:
This routine gets the exchange associated with a buffer
Arguments:
pServerEntry - the servere entry
pBuffer - the buffer instance.
Return Value:
a valid SMB_EXCHANGE instance if successful, otheriwse NULL.
Notes:
This routine and the routines that follow enable a pipelined reuse of MID's
If a large buffer is to be copied then this can be done without hodling onto
a MID. This improves the throughput between the client and the server. At the
very least this mechanism ensures that the connection engine will not be the
constraining factor in MID reuse.
--*/
{
PSMBCEDB_REQUEST_ENTRY pRequestEntry;
PSMB_EXCHANGE pExchange = NULL;
// Acquire the resource
SmbCeAcquireSpinLock();
// Walk through the list of requests maintained on this and remove the one
// matching the cached buffer ptr with the ptr indicated
pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
while (pRequestEntry != NULL) {
if ((pRequestEntry->GenericRequest.Type == COPY_DATA_REQUEST) &&
(pRequestEntry->CopyDataRequest.pBuffer == pBuffer)) {
pExchange = pRequestEntry->CopyDataRequest.pExchange;
pRequestEntry->CopyDataRequest.pBuffer = NULL;
break;
}
pRequestEntry = SmbCeGetNextRequestEntry(
&pServerEntry->OutstandingRequests,
pRequestEntry);
}
// Release the resource
SmbCeReleaseSpinLock();
return pExchange;
}
NTSTATUS
SmbCeAssociateBufferWithExchange(
PSMBCEDB_SERVER_ENTRY pServerEntry,
struct _SMB_EXCHANGE * pExchange,
PVOID pBuffer)
/*++
Routine Description:
This routine establishes an association between an exchange and a copy data request
buffer
Arguments:
pServerEntry - the servere entry
pBuffer - the buffer instance.
Return Value:
STATUS_SUCCESS if succesful
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PSMBCEDB_REQUEST_ENTRY pRequestEntry;
// Acquire the resource
SmbCeAcquireSpinLock();
Status = pServerEntry->ServerStatus;
if (Status == STATUS_SUCCESS) {
// Walk through the list of requests maintained on this and remove the one
// matching the cached buffer ptr with the ptr indicated
pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
while (pRequestEntry != NULL) {
if ((pRequestEntry->GenericRequest.Type == COPY_DATA_REQUEST) &&
(pRequestEntry->CopyDataRequest.pBuffer == NULL)) {
pRequestEntry->CopyDataRequest.pExchange = pExchange;
pRequestEntry->CopyDataRequest.pBuffer = pBuffer;
break;
}
pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
}
}
// Release the resource
SmbCeReleaseSpinLock();
if ((Status == STATUS_SUCCESS) &&
(pRequestEntry == NULL)) {
// Allocate a new entry and add it to the list.
pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
if (pRequestEntry != NULL) {
// Enqueue the request entry.
pRequestEntry->CopyDataRequest.Type = COPY_DATA_REQUEST;
pRequestEntry->CopyDataRequest.pExchange = pExchange;
pRequestEntry->CopyDataRequest.pBuffer = pBuffer;
// Acquire the resource
SmbCeAcquireSpinLock();
if ((Status = pServerEntry->ServerStatus) == STATUS_SUCCESS) {
SmbCeAddRequestEntryLite(&pServerEntry->OutstandingRequests,pRequestEntry);
}
// Release the resource
SmbCeReleaseSpinLock();
if (Status != STATUS_SUCCESS) {
SmbCeTearDownRequestEntry(pRequestEntry);
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
return Status;
}
VOID
SmbCePurgeBuffersAssociatedWithExchange(
PSMBCEDB_SERVER_ENTRY pServerEntry,
struct _SMB_EXCHANGE * pExchange)
/*++
Routine Description:
This routine purges all the copy data requests associated with an exchange.
Arguments:
pServerEntry - the servere entry
pExchange - the exchange instance.
Notes:
This mechanism of delaying the purging of requests associated with an exchange
till it is discared is intended to solve the problem of repeated allocation/freeing
of request entries. This rests on the assumption that there will not be too many
copy data requests outstanding for any exchange. If evidence to the contrary is
noticed this technique has to be modified.
--*/
{
SMBCEDB_REQUESTS ExchangeRequests;
PSMBCEDB_REQUEST_ENTRY pRequestEntry;
PSMBCEDB_REQUEST_ENTRY pNextRequestEntry;
SmbCeInitializeRequests(&ExchangeRequests);
// Acquire the resource
SmbCeAcquireSpinLock();
// Walk through the list of requests maintained on this and remove the one
// matching the given exchange
pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
while (pRequestEntry != NULL) {
pNextRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
if (pRequestEntry->GenericRequest.pExchange == pExchange) {
SmbCeRemoveRequestEntryLite(&pServerEntry->OutStandingRequests,pRequestEntry);
SmbCeAddRequestEntryLite(&ExchangeRequests,pRequestEntry);
}
pRequestEntry = pNextRequestEntry;
}
// Release the resource
SmbCeReleaseSpinLock();
pRequestEntry = SmbCeGetFirstRequestEntry(&ExchangeRequests);
while (pRequestEntry != NULL) {
SmbCeRemoveRequestEntryLite(&ExchangeRequests,pRequestEntry);
SmbCeTearDownRequestEntry(pRequestEntry);
pRequestEntry = SmbCeGetFirstRequestEntry(&ExchangeRequests);
}
}