Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
14 KiB

  1. /*++ BUILD Version: 0009 // Increment this if a change has global effects
  2. Copyright (c) 1987-1993 Microsoft Corporation
  3. Module Name:
  4. transact.c
  5. Abstract:
  6. This file implements the MDL substring functions and tests.
  7. Author:
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #include "align.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, MRxSmbDbgDumpMdlChain)
  14. #pragma alloc_text(PAGE, MRxSmbBuildMdlSubChain)
  15. #pragma alloc_text(PAGE, MRxSmbFinalizeMdlSubChain)
  16. #pragma alloc_text(PAGE, MRxSmbTestStudCode)
  17. #endif
  18. //RXDT_DefineCategory(TRANSACT);
  19. extern DEBUG_TRACE_CONTROLPOINT RX_DEBUG_TRACE_TRANSACT;
  20. #define Dbg (DEBUG_TRACE_TRANSACT)
  21. #if DBG
  22. VOID
  23. MRxSmbDbgDumpMdlChain (
  24. PMDL MdlChain,
  25. PMDL WatchMdl,
  26. PSZ Tagstring
  27. )
  28. /*++
  29. dumps chain with counts and buffers....watches for the watchmdl and prints the next field
  30. if it is encountered.
  31. --*/
  32. {
  33. ULONG i,total;
  34. PSZ watchstring;
  35. PAGED_CODE();
  36. RxDbgTrace(+1,Dbg,("DbgDumpMdlChain: %s\n",Tagstring));
  37. for (total=i=0;MdlChain!=NULL;i++,MdlChain=MdlChain->Next) {
  38. if (MdlChain==WatchMdl) {
  39. if (MdlChain->Next==NULL) {
  40. watchstring = "gooddwatch";
  41. } else {
  42. watchstring = "badwatch";
  43. }
  44. } else {
  45. watchstring = "";
  46. }
  47. total+=MdlChain->ByteCount;
  48. RxDbgTrace(0,Dbg,("--->%02d %08lx %08lx %6d %6d %s\n",i,MdlChain,
  49. MmGetMdlVirtualAddress(MdlChain),MdlChain->ByteCount,total,watchstring));
  50. }
  51. RxDbgTraceUnIndent(-1,Dbg);
  52. }
  53. NTSTATUS
  54. MRxSmbBuildMdlSubChain (
  55. PMDLSUB_CHAIN_STATE state,
  56. ULONG Options,
  57. PMDL InputMdlChain,
  58. ULONG TotalListSize,
  59. ULONG FirstByteToSend,
  60. ULONG BytesToSend
  61. )
  62. /*++
  63. Routine Description:
  64. This routine returns an mdl chain that describes the bytes from
  65. [FirstByteToSend,FirstByteToSend+BytesToSend-1]
  66. (origin zero) from the "string of bytes" described by the InputMdlChain
  67. we do this by the following steps:
  68. a) find the subsequence of MDLs that contain the substring
  69. b) if either the first or the last is not used completely then build a partial
  70. to describe it (taking cognizance of the special case where first=last)
  71. c) save the ->Next field of the last; set it to zero. also, find out how many
  72. extra bytes are available on the MDL (i.e. how many bytes are on the same page
  73. as the last described byte but are not described.
  74. there are the following cases:
  75. 1) a suffix chain of the original chain describes the message
  76. 2) the message fits within a single original mdl (and not case 1 or 2b); return a partial
  77. 2b) the message is exactly one block! no partial but muck the chain.
  78. 3) a suffix chain can be formed by partialing the first containing MDL
  79. 4) the msg ends exactly on a MDL boundary...front may or may not be partialed
  80. 5) the msg ends in a partial but not case (2)
  81. (2b), (4), and (5) cause a chain fixup...but (5) is not the same chain fixup.
  82. (3) causes a partial; (5) causes one or two partials.
  83. Arguments:
  84. as described in the text above. plus
  85. FirstTime - indicates if the structure should be cleared initially
  86. Return Value:
  87. RXSTATUS - The return status for the operation.
  88. SUCCESS - if no allocation problems
  89. INSUFFICIENT_RESOURCES - if couldn't allocate a partial
  90. Notes:
  91. --*/
  92. {
  93. NTSTATUS Status = RX_MAP_STATUS(SUCCESS);
  94. ULONG PrefixBytes = 0;
  95. ULONG FirstByteNotToSend;
  96. PMDL BeforeTheLastMdl,LastMdl;
  97. ULONG RemainingListSize = TotalListSize;
  98. PMDL OriginalFirstMdl = InputMdlChain;
  99. PMDL PreviousMdl = NULL;
  100. ULONG ThisCount,Offset,AvailableBytesThisRecord;
  101. ULONG WhichCase = 0;
  102. PAGED_CODE();
  103. RxDbgTrace(+1,Dbg,("MRxSmbBuildMdlSubChain: tot,1st,size %d,%d,%d \n",
  104. TotalListSize,FirstByteToSend,BytesToSend
  105. ));
  106. ASSERT (BytesToSend>0);
  107. ASSERT (TotalListSize>FirstByteToSend);
  108. ASSERT (TotalListSize>=FirstByteToSend+BytesToSend);
  109. if (FlagOn(Options,SMBMRX_BUILDSUBCHAIN_DUMPCHAININ)) {
  110. MRxSmbDbgDumpMdlChain(InputMdlChain,NULL,"Input Chain......");
  111. }
  112. if (FlagOn(Options,SMBMRX_BUILDSUBCHAIN_FIRSTTIME)) {
  113. RtlZeroMemory(state,sizeof(*state));
  114. }
  115. //CODE.IMPROVEMENT we could make this go much faster if we would cache how far
  116. // we got in the list last time
  117. BeforeTheLastMdl = NULL;
  118. for (;;) {
  119. ThisCount = OriginalFirstMdl->ByteCount;
  120. if ( (ThisCount+PrefixBytes) > FirstByteToSend) break;
  121. RemainingListSize -= ThisCount;
  122. PrefixBytes += ThisCount;
  123. RxDbgTrace(0,Dbg,("-->pfxsize %d \n", PrefixBytes));
  124. OriginalFirstMdl = OriginalFirstMdl->Next;
  125. }
  126. //case (1) the rest of the list describes this string perfectly. so
  127. // don't allocate anything and just get out. we still have to
  128. // run the list to find the last pointer
  129. if (RemainingListSize == BytesToSend) {
  130. PMDL last;
  131. RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(1) \n"));
  132. last = state->FirstMdlOut = OriginalFirstMdl;
  133. for (;last->Next!=NULL;last=last->Next);
  134. state->LastMdlOut = last;
  135. DebugDoit(WhichCase = 1);
  136. goto FINALLY;
  137. } else {
  138. RxDbgTrace(0,Dbg,("-->NOT CASE 1, pfxsize %d \n", PrefixBytes));
  139. RemainingListSize -= ThisCount;
  140. }
  141. //either we need to partial this mdl OR we have to hack the list end OR both
  142. Offset = FirstByteToSend - PrefixBytes;
  143. AvailableBytesThisRecord = ThisCount-Offset;
  144. if ( (Offset != 0) || (BytesToSend<AvailableBytesThisRecord) ) {
  145. //we need a partial....sigh
  146. state->FirstMdlOut = RxAllocateMdl(0,ThisCount);
  147. if (state->FirstMdlOut==NULL) {
  148. Status = RX_MAP_STATUS(INSUFFICIENT_RESOURCES);
  149. goto FINALLY;
  150. }
  151. state->FirstMdlWasAllocated = TRUE;
  152. RxBuildPartialMdlUsingOffset(OriginalFirstMdl,state->FirstMdlOut,Offset,min(BytesToSend,AvailableBytesThisRecord));
  153. if (BytesToSend<=AvailableBytesThisRecord) {
  154. RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(2) \n"));
  155. //case (2) this block completely contains the substring...cool.
  156. state->LastMdlOut = state->FirstMdlOut;
  157. state->FirstMdlOut->Next = NULL;
  158. DebugDoit(WhichCase = 2);
  159. goto FINALLY;
  160. }
  161. state->FirstMdlOut->Next = OriginalFirstMdl->Next; //fix up the chain
  162. //case(3) the rest of the list could be perfect! still gotta run the list tho.....
  163. //moved up RemainingListSize -= ThisCount;
  164. if ( RemainingListSize == BytesToSend-AvailableBytesThisRecord) {
  165. PMDL last;
  166. RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(3) \n"));
  167. last = state->FirstMdlOut;
  168. for (;last->Next!=NULL;last=last->Next);
  169. state->LastMdlOut = last;
  170. DebugDoit(WhichCase = 3);
  171. goto FINALLY;
  172. }
  173. } else {
  174. RxDbgTrace(0,Dbg,("-->NO NEED FOR FIRST PARTIAL\n"));
  175. state->FirstMdlOut = OriginalFirstMdl;
  176. if ((Offset==0)&&(BytesToSend==AvailableBytesThisRecord)) {
  177. RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(2b) ...sigh\n"));
  178. //case (2b) this block matches the substring...no partial but muck with the next pointer.
  179. state->LastMdlOut = state->FirstMdlOut;
  180. state->ActualLastMdl = OriginalFirstMdl;
  181. state->ActualLastMdl_Next = OriginalFirstMdl->Next;
  182. state->FirstMdlOut->Next = NULL;
  183. DebugDoit(WhichCase = 2);
  184. goto FINALLY;
  185. }
  186. }
  187. //we don't know yet whether we have to partial the last...but we know that we'll have
  188. //to do a chain fixup/
  189. FirstByteNotToSend = FirstByteToSend + BytesToSend;
  190. BeforeTheLastMdl = state->FirstMdlOut;
  191. PrefixBytes+=ThisCount; //we're actully passing the current record
  192. for (;;) {
  193. LastMdl = BeforeTheLastMdl->Next;
  194. ASSERT(LastMdl);
  195. ThisCount = LastMdl->ByteCount;
  196. RxDbgTrace(0,Dbg,("-->(loop2)pfx,rem,count,1st %d,%d,%d,%d \n",
  197. PrefixBytes,RemainingListSize,ThisCount,FirstByteNotToSend));
  198. if ( (ThisCount+PrefixBytes) == FirstByteNotToSend ) {
  199. ///case (4): no partial at the end..just fix up the last link
  200. RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(4) \n"));
  201. state->LastMdlOut = LastMdl;
  202. state->ActualLastMdl = LastMdl;
  203. state->ActualLastMdl_Next = LastMdl->Next;
  204. state->LastMdlOut->Next = NULL;
  205. DebugDoit(WhichCase = 4);
  206. goto FINALLY;
  207. }
  208. if ( (ThisCount+PrefixBytes) > FirstByteNotToSend) break;
  209. RemainingListSize -= ThisCount;
  210. ASSERT(RemainingListSize>0);
  211. PrefixBytes += ThisCount;
  212. BeforeTheLastMdl = BeforeTheLastMdl->Next;
  213. }
  214. //case (5): [THE LAST CASE!!!!] we have to partial the last guy so the chain fixup
  215. // is different
  216. RxDbgTrace(0,Dbg,("MRxSmbBuildMdlSubChain:(5) \n"));
  217. state->LastMdlOut = RxAllocateMdl(0,ThisCount);
  218. if (state->LastMdlOut==NULL) {
  219. Status = RX_MAP_STATUS(INSUFFICIENT_RESOURCES);
  220. goto FINALLY;
  221. }
  222. state->LastMdlWasAllocated = TRUE;
  223. RxBuildPartialMdlUsingOffset(LastMdl,state->LastMdlOut,0,FirstByteNotToSend-PrefixBytes);
  224. state->OneBeforeActualLastMdl = BeforeTheLastMdl;
  225. state->ActualLastMdl = LastMdl;
  226. state->ActualLastMdl_Next = LastMdl->Next;
  227. BeforeTheLastMdl->Next = state->LastMdlOut;
  228. state->LastMdlOut->Next = NULL;
  229. DebugDoit(WhichCase = 5);
  230. FINALLY:
  231. if (Status==RX_MAP_STATUS(SUCCESS)) {
  232. ASSERT(state->LastMdlOut->Next == NULL);
  233. if (FlagOn(Options,SMBMRX_BUILDSUBCHAIN_DUMPCHAININ)) {
  234. MRxSmbDbgDumpMdlChain(state->FirstMdlOut,state->LastMdlOut,"AND THE RESULT ------------");
  235. }
  236. } else {
  237. MRxSmbFinalizeMdlSubChain(state);
  238. }
  239. RxDbgTrace(-1,Dbg,("MRxSmbBuildMdlSubChain:case(%u) status %08lx \n",WhichCase,Status));
  240. return(Status);
  241. }
  242. VOID
  243. MRxSmbFinalizeMdlSubChain (
  244. PMDLSUB_CHAIN_STATE state
  245. )
  246. /*++
  247. Routine Description:
  248. This routine finalizes a MDL chain by putting it back as it was.
  249. Arguments:
  250. state - a structure describing the mdl-subchain and what the original looked like
  251. Return Value:
  252. Notes:
  253. --*/
  254. {
  255. PAGED_CODE();
  256. ASSERT(state->PadBytesAvailable==0);
  257. ASSERT(state->PadBytesAdded==0);
  258. //first restore the chain
  259. if (state->OneBeforeActualLastMdl) {
  260. state->OneBeforeActualLastMdl->Next = state->ActualLastMdl;
  261. }
  262. if (state->ActualLastMdl) {
  263. state->ActualLastMdl->Next = state->ActualLastMdl_Next;
  264. }
  265. //restore the count on the last mdl
  266. state->LastMdlOut -= state->PadBytesAdded;
  267. //get rid of the MDLs
  268. if (state->FirstMdlWasAllocated) {
  269. IoFreeMdl(state->FirstMdlOut);
  270. }
  271. if (state->LastMdlWasAllocated) {
  272. IoFreeMdl(state->LastMdlOut);
  273. }
  274. }
  275. LONG MRxSmbNeedSCTesting = 1;
  276. VOID MRxSmbTestStudCode(void)
  277. {
  278. PMDL Md11,Mdl2,Mdl4,Mdlx;
  279. PMDL ch;
  280. ULONG i,j;
  281. ULONG LastSize=1;
  282. ULONG TotalSize = LastSize+7;
  283. UCHAR dbgmssg[16],savedmsg[16];
  284. UCHAR reconstructedmsg[16];
  285. MDLSUB_CHAIN_STATE state;
  286. PAGED_CODE();
  287. ASSERT (TotalSize<=16);
  288. if (InterlockedExchange(&MRxSmbNeedSCTesting,0)==0) {
  289. return;
  290. }
  291. Mdl4 = RxAllocateMdl(dbgmssg+0,4);
  292. Mdl2 = RxAllocateMdl(dbgmssg+4,2);
  293. Md11 = RxAllocateMdl(dbgmssg+6,1);
  294. Mdlx = RxAllocateMdl(dbgmssg+7,LastSize);
  295. if ((Mdl4==NULL)||(Mdl2==NULL)||(Md11==NULL)||(Mdlx==NULL)) {
  296. DbgPrint("NoMDLS in teststudcode.......\n");
  297. //DbgBreakPoint();
  298. goto FINALLY;
  299. }
  300. MmBuildMdlForNonPagedPool(Md11);
  301. MmBuildMdlForNonPagedPool(Mdl2);
  302. MmBuildMdlForNonPagedPool(Mdl4);
  303. MmBuildMdlForNonPagedPool(Mdlx);
  304. Mdl4->Next = Mdl2;
  305. Mdl2->Next = Md11;
  306. Md11->Next = Mdlx;
  307. Mdlx->Next = NULL;
  308. for (i=0;i<10;i++) { dbgmssg[i] = '0'+(UCHAR)i; }
  309. for (j=0;i<16;i++,j++) { dbgmssg[i] = 'a'+(UCHAR)j; }
  310. RxDbgTrace(0,Dbg,("TestStudCode dbgmssg=%*.*s\n",16,16,dbgmssg));
  311. for (j=0;j<16;j++) { savedmsg[j] = dbgmssg[j]; }
  312. for (i=0;i<TotalSize;i++) {
  313. // for (i=1;i<TotalSize;i++) {
  314. for (j=i;j<TotalSize;j++) {
  315. ULONG size = j-i+1;
  316. ULONG k;BOOLEAN printflag;
  317. //RxDbgTrace(0,Dbg,("TestStudCode %d %d %*.*s\n",i,size,size,size,dbgmssg+i));
  318. printflag = RxDbgTraceDisableGlobally();//this is debug code anyway!
  319. MRxSmbBuildMdlSubChain(&state,SMBMRX_BUILDSUBCHAIN_FIRSTTIME,Mdl4,TotalSize,i,size);
  320. RxDbgTraceEnableGlobally(printflag);
  321. for (k=0,ch=state.FirstMdlOut;ch!=NULL;ch=ch->Next) {
  322. RtlCopyMemory(reconstructedmsg+k,MmGetMdlVirtualAddress(ch),ch->ByteCount);
  323. k+= ch->ByteCount;
  324. }
  325. if ((k!=size) || (memcmp(dbgmssg+i,reconstructedmsg,k)!=0) ) {
  326. RxDbgTrace(0,Dbg,("TestStudCode %d %d %*.*s\n",i,size,size,size,dbgmssg+i));
  327. RxDbgTrace(0,Dbg,("TestStudCode recmssg=%*.*s\n",k,k,reconstructedmsg));
  328. }
  329. MRxSmbFinalizeMdlSubChain(&state);
  330. for (k=0,ch=Mdl4;ch!=NULL;ch=ch->Next) {
  331. RtlCopyMemory(reconstructedmsg+k,MmGetMdlVirtualAddress(ch),ch->ByteCount);
  332. k+= ch->ByteCount;
  333. }
  334. if ((k!=TotalSize) || (memcmp(dbgmssg,reconstructedmsg,k)!=0) ) {
  335. RxDbgTrace(0,Dbg,("TestStudCodxxxe %d %d %*.*s\n",i,size,size,size,dbgmssg+i));
  336. RxDbgTrace(0,Dbg,("TestStudCode xxxrecmssg=%*.*s\n",k,k,reconstructedmsg));
  337. }
  338. //ASSERT(!"okay to go???");
  339. }
  340. }
  341. FINALLY:
  342. if (Mdl4) IoFreeMdl(Mdl4);
  343. if (Mdl2) IoFreeMdl(Mdl2);
  344. if (Md11) IoFreeMdl(Md11);
  345. if (Mdlx) IoFreeMdl(Mdlx);
  346. RxDbgTrace(0,Dbg,("TestStudCodeEND \n"));
  347. }
  348. #endif