windows-nt/Source/XPSP1/NT/base/fs/rdr2/rdbss/smb.mrx/manipmdl.c

420 lines
14 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++ BUILD Version: 0009 // Increment this if a change has global effects
Copyright (c) 1987-1993 Microsoft Corporation
Module Name:
transact.c
Abstract:
This file implements the MDL substring functions and tests.
Author:
--*/
#include "precomp.h"
#pragma hdrstop
#include "align.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, MRxSmbDbgDumpMdlChain)
#pragma alloc_text(PAGE, MRxSmbBuildMdlSubChain)
#pragma alloc_text(PAGE, MRxSmbFinalizeMdlSubChain)
#pragma alloc_text(PAGE, MRxSmbTestStudCode)
#endif
//RXDT_DefineCategory(TRANSACT);
extern DEBUG_TRACE_CONTROLPOINT RX_DEBUG_TRACE_TRANSACT;
#define Dbg (DEBUG_TRACE_TRANSACT)
#if DBG
VOID
MRxSmbDbgDumpMdlChain (
PMDL MdlChain,
PMDL WatchMdl,
PSZ Tagstring
)
/*++
dumps chain with counts and buffers....watches for the watchmdl and prints the next field
if it is encountered.
--*/
{
ULONG i,total;
PSZ watchstring;
PAGED_CODE();
RxDbgTrace(+1,Dbg,("DbgDumpMdlChain: %s\n",Tagstring));
for (total=i=0;MdlChain!=NULL;i++,MdlChain=MdlChain->Next) {
if (MdlChain==WatchMdl) {
if (MdlChain->Next==NULL) {
watchstring = "gooddwatch";
} else {
watchstring = "badwatch";
}
} else {
watchstring = "";
}
total+=MdlChain->ByteCount;
RxDbgTrace(0,Dbg,("--->%02d %08lx %08lx %6d %6d %s\n",i,MdlChain,
MmGetMdlVirtualAddress(MdlChain),MdlChain->ByteCount,total,watchstring));
}
RxDbgTraceUnIndent(-1,Dbg);
}
#endif
NTSTATUS
MRxSmbBuildMdlSubChain (
PMDLSUB_CHAIN_STATE state,
ULONG Options,
PMDL InputMdlChain,
ULONG TotalListSize,
ULONG FirstByteToSend,
ULONG BytesToSend
)
/*++
Routine Description:
This routine returns an mdl chain that describes the bytes from
[FirstByteToSend,FirstByteToSend+BytesToSend-1]
(origin zero) from the "string of bytes" described by the InputMdlChain
we do this by the following steps:
a) find the subsequence of MDLs that contain the substring
b) if either the first or the last is not used completely then build a partial
to describe it (taking cognizance of the special case where first=last)
c) save the ->Next field of the last; set it to zero. also, find out how many
extra bytes are available on the MDL (i.e. how many bytes are on the same page
as the last described byte but are not described.
there are the following cases:
1) a suffix chain of the original chain describes the message
2) the message fits within a single original mdl (and not case 1 or 2b); return a partial
2b) the message is exactly one block! no partial but muck the chain.
3) a suffix chain can be formed by partialing the first containing MDL
4) the msg ends exactly on a MDL boundary...front may or may not be partialed
5) the msg ends in a partial but not case (2)
(2b), (4), and (5) cause a chain fixup...but (5) is not the same chain fixup.
(3) causes a partial; (5) causes one or two partials.
Arguments:
as described in the text above. plus
FirstTime - indicates if the structure should be cleared initially
Return Value:
RXSTATUS - The return status for the operation.
SUCCESS - if no allocation problems
INSUFFICIENT_RESOURCES - if couldn't allocate a partial
Notes:
--*/
{
NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
ULONG PrefixBytes = 0;
ULONG FirstByteNotToSend;
PMDL BeforeTheLastMdl,LastMdl;
ULONG RemainingListSize = TotalListSize;
PMDL OriginalFirstMdl = InputMdlChain;
PMDL PreviousMdl = NULL;
ULONG ThisCount,Offset,AvailableBytesThisRecord;
#if DBG
ULONG WhichCase = 0;
#endif
PAGED_CODE();
RxDbgTrace(+1,Dbg,("MRxSmbBuildMdlSubChain: tot,1st,size %d,%d,%d \n",
TotalListSize,FirstByteToSend,BytesToSend
));
ASSERT (BytesToSend>0);
ASSERT (TotalListSize>FirstByteToSend);
ASSERT (TotalListSize>=FirstByteToSend+BytesToSend);
if (FlagOn(Options,SMBMRX_BUILDSUBCHAIN_DUMPCHAININ)) {
MRxSmbDbgDumpMdlChain(InputMdlChain,NULL,"Input Chain......");
}
if (FlagOn(Options,SMBMRX_BUILDSUBCHAIN_FIRSTTIME)) {
RtlZeroMemory(state,sizeof(*state));
}
//CODE.IMPROVEMENT we could make this go much faster if we would cache how far
// we got in the list last time
BeforeTheLastMdl = NULL;
for (;;) {
ThisCount = OriginalFirstMdl->ByteCount;
if ( (ThisCount+PrefixBytes) > FirstByteToSend) break;
RemainingListSize -= ThisCount;
PrefixBytes += ThisCount;
RxDbgTrace(0,Dbg,("-->pfxsize %d \n", PrefixBytes));
OriginalFirstMdl = OriginalFirstMdl->Next;
}
//case (1) the rest of the list describes this string perfectly. so
// don't allocate anything and just get out. we still have to
// run the list to find the last pointer
if (RemainingListSize == BytesToSend) {
PMDL last;
RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(1) \n"));
last = state->FirstMdlOut = OriginalFirstMdl;
for (;last->Next!=NULL;last=last->Next);
state->LastMdlOut = last;
DebugDoit(WhichCase = 1);
goto FINALLY;
} else {
RxDbgTrace(0,Dbg,("-->NOT CASE 1, pfxsize %d \n", PrefixBytes));
RemainingListSize -= ThisCount;
}
//either we need to partial this mdl OR we have to hack the list end OR both
Offset = FirstByteToSend - PrefixBytes;
AvailableBytesThisRecord = ThisCount-Offset;
if ( (Offset != 0) || (BytesToSend<AvailableBytesThisRecord) ) {
//we need a partial....sigh
state->FirstMdlOut = RxAllocateMdl(0,ThisCount);
if (state->FirstMdlOut==NULL) {
Status = RX_MAP_STATUS(INSUFFICIENT_RESOURCES);
goto FINALLY;
}
state->FirstMdlWasAllocated = TRUE;
RxBuildPartialMdlUsingOffset(OriginalFirstMdl,state->FirstMdlOut,Offset,min(BytesToSend,AvailableBytesThisRecord));
if (BytesToSend<=AvailableBytesThisRecord) {
RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(2) \n"));
//case (2) this block completely contains the substring...cool.
state->LastMdlOut = state->FirstMdlOut;
state->FirstMdlOut->Next = NULL;
DebugDoit(WhichCase = 2);
goto FINALLY;
}
state->FirstMdlOut->Next = OriginalFirstMdl->Next; //fix up the chain
//case(3) the rest of the list could be perfect! still gotta run the list tho.....
//moved up RemainingListSize -= ThisCount;
if ( RemainingListSize == BytesToSend-AvailableBytesThisRecord) {
PMDL last;
RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(3) \n"));
last = state->FirstMdlOut;
for (;last->Next!=NULL;last=last->Next);
state->LastMdlOut = last;
DebugDoit(WhichCase = 3);
goto FINALLY;
}
} else {
RxDbgTrace(0,Dbg,("-->NO NEED FOR FIRST PARTIAL\n"));
state->FirstMdlOut = OriginalFirstMdl;
if ((Offset==0)&&(BytesToSend==AvailableBytesThisRecord)) {
RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(2b) ...sigh\n"));
//case (2b) this block matches the substring...no partial but muck with the next pointer.
state->LastMdlOut = state->FirstMdlOut;
state->ActualLastMdl = OriginalFirstMdl;
state->ActualLastMdl_Next = OriginalFirstMdl->Next;
state->FirstMdlOut->Next = NULL;
DebugDoit(WhichCase = 2);
goto FINALLY;
}
}
//we don't know yet whether we have to partial the last...but we know that we'll have
//to do a chain fixup/
FirstByteNotToSend = FirstByteToSend + BytesToSend;
BeforeTheLastMdl = state->FirstMdlOut;
PrefixBytes+=ThisCount; //we're actully passing the current record
for (;;) {
LastMdl = BeforeTheLastMdl->Next;
ASSERT(LastMdl);
ThisCount = LastMdl->ByteCount;
RxDbgTrace(0,Dbg,("-->(loop2)pfx,rem,count,1st %d,%d,%d,%d \n",
PrefixBytes,RemainingListSize,ThisCount,FirstByteNotToSend));
if ( (ThisCount+PrefixBytes) == FirstByteNotToSend ) {
///case (4): no partial at the end..just fix up the last link
RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(4) \n"));
state->LastMdlOut = LastMdl;
state->ActualLastMdl = LastMdl;
state->ActualLastMdl_Next = LastMdl->Next;
state->LastMdlOut->Next = NULL;
DebugDoit(WhichCase = 4);
goto FINALLY;
}
if ( (ThisCount+PrefixBytes) > FirstByteNotToSend) break;
RemainingListSize -= ThisCount;
ASSERT(RemainingListSize>0);
PrefixBytes += ThisCount;
BeforeTheLastMdl = BeforeTheLastMdl->Next;
}
//case (5): [THE LAST CASE!!!!] we have to partial the last guy so the chain fixup
// is different
RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(5) \n"));
state->LastMdlOut = RxAllocateMdl(0,ThisCount);
if (state->LastMdlOut==NULL) {
Status = RX_MAP_STATUS(INSUFFICIENT_RESOURCES);
goto FINALLY;
}
state->LastMdlWasAllocated = TRUE;
RxBuildPartialMdlUsingOffset(LastMdl,state->LastMdlOut,0,FirstByteNotToSend-PrefixBytes);
state->OneBeforeActualLastMdl = BeforeTheLastMdl;
state->ActualLastMdl = LastMdl;
state->ActualLastMdl_Next = LastMdl->Next;
BeforeTheLastMdl->Next = state->LastMdlOut;
state->LastMdlOut->Next = NULL;
DebugDoit(WhichCase = 5);
FINALLY:
if (Status==RX_MAP_STATUS(SUCCESS)) {
ASSERT(state->LastMdlOut->Next == NULL);
if (FlagOn(Options,SMBMRX_BUILDSUBCHAIN_DUMPCHAININ)) {
MRxSmbDbgDumpMdlChain(state->FirstMdlOut,state->LastMdlOut,"AND THE RESULT ------------");
}
} else {
MRxSmbFinalizeMdlSubChain(state);
}
RxDbgTrace(-1,Dbg,("MRxSmbBuildMdlSubChain:case(%u) status %08lx \n",WhichCase,Status));
return(Status);
}
VOID
MRxSmbFinalizeMdlSubChain (
PMDLSUB_CHAIN_STATE state
)
/*++
Routine Description:
This routine finalizes a MDL chain by putting it back as it was.
Arguments:
state - a structure describing the mdl-subchain and what the original looked like
Return Value:
Notes:
--*/
{
PAGED_CODE();
ASSERT(state->PadBytesAvailable==0);
ASSERT(state->PadBytesAdded==0);
//first restore the chain
if (state->OneBeforeActualLastMdl) {
state->OneBeforeActualLastMdl->Next = state->ActualLastMdl;
}
if (state->ActualLastMdl) {
state->ActualLastMdl->Next = state->ActualLastMdl_Next;
}
//restore the count on the last mdl
state->LastMdlOut -= state->PadBytesAdded;
//get rid of the MDLs
if (state->FirstMdlWasAllocated) {
IoFreeMdl(state->FirstMdlOut);
}
if (state->LastMdlWasAllocated) {
IoFreeMdl(state->LastMdlOut);
}
}
#if DBG
LONG MRxSmbNeedSCTesting = 1;
VOID MRxSmbTestStudCode(void)
{
PMDL Md11,Mdl2,Mdl4,Mdlx;
PMDL ch;
ULONG i,j;
ULONG LastSize=1;
ULONG TotalSize = LastSize+7;
UCHAR dbgmssg[16],savedmsg[16];
UCHAR reconstructedmsg[16];
MDLSUB_CHAIN_STATE state;
PAGED_CODE();
ASSERT (TotalSize<=16);
if (InterlockedExchange(&MRxSmbNeedSCTesting,0)==0) {
return;
}
Mdl4 = RxAllocateMdl(dbgmssg+0,4);
Mdl2 = RxAllocateMdl(dbgmssg+4,2);
Md11 = RxAllocateMdl(dbgmssg+6,1);
Mdlx = RxAllocateMdl(dbgmssg+7,LastSize);
if ((Mdl4==NULL)||(Mdl2==NULL)||(Md11==NULL)||(Mdlx==NULL)) {
DbgPrint("NoMDLS in teststudcode.......\n");
//DbgBreakPoint();
goto FINALLY;
}
MmBuildMdlForNonPagedPool(Md11);
MmBuildMdlForNonPagedPool(Mdl2);
MmBuildMdlForNonPagedPool(Mdl4);
MmBuildMdlForNonPagedPool(Mdlx);
Mdl4->Next = Mdl2;
Mdl2->Next = Md11;
Md11->Next = Mdlx;
Mdlx->Next = NULL;
for (i=0;i<10;i++) { dbgmssg[i] = '0'+(UCHAR)i; }
for (j=0;i<16;i++,j++) { dbgmssg[i] = 'a'+(UCHAR)j; }
RxDbgTrace(0,Dbg,("TestStudCode dbgmssg=%*.*s\n",16,16,dbgmssg));
for (j=0;j<16;j++) { savedmsg[j] = dbgmssg[j]; }
for (i=0;i<TotalSize;i++) {
// for (i=1;i<TotalSize;i++) {
for (j=i;j<TotalSize;j++) {
ULONG size = j-i+1;
ULONG k;BOOLEAN printflag;
//RxDbgTrace(0,Dbg,("TestStudCode %d %d %*.*s\n",i,size,size,size,dbgmssg+i));
printflag = RxDbgTraceDisableGlobally();//this is debug code anyway!
MRxSmbBuildMdlSubChain(&state,SMBMRX_BUILDSUBCHAIN_FIRSTTIME,Mdl4,TotalSize,i,size);
RxDbgTraceEnableGlobally(printflag);
for (k=0,ch=state.FirstMdlOut;ch!=NULL;ch=ch->Next) {
RtlCopyMemory(reconstructedmsg+k,MmGetMdlVirtualAddress(ch),ch->ByteCount);
k+= ch->ByteCount;
}
if ((k!=size) || (memcmp(dbgmssg+i,reconstructedmsg,k)!=0) ) {
RxDbgTrace(0,Dbg,("TestStudCode %d %d %*.*s\n",i,size,size,size,dbgmssg+i));
RxDbgTrace(0,Dbg,("TestStudCode recmssg=%*.*s\n",k,k,reconstructedmsg));
}
MRxSmbFinalizeMdlSubChain(&state);
for (k=0,ch=Mdl4;ch!=NULL;ch=ch->Next) {
RtlCopyMemory(reconstructedmsg+k,MmGetMdlVirtualAddress(ch),ch->ByteCount);
k+= ch->ByteCount;
}
if ((k!=TotalSize) || (memcmp(dbgmssg,reconstructedmsg,k)!=0) ) {
RxDbgTrace(0,Dbg,("TestStudCodxxxe %d %d %*.*s\n",i,size,size,size,dbgmssg+i));
RxDbgTrace(0,Dbg,("TestStudCode xxxrecmssg=%*.*s\n",k,k,reconstructedmsg));
}
//ASSERT(!"okay to go???");
}
}
FINALLY:
if (Mdl4) IoFreeMdl(Mdl4);
if (Mdl2) IoFreeMdl(Mdl2);
if (Md11) IoFreeMdl(Md11);
if (Mdlx) IoFreeMdl(Mdlx);
RxDbgTrace(0,Dbg,("TestStudCodeEND \n"));
}
#endif