Source code of Windows XP (NT5)
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.

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