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.

1127 lines
28 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. cachemdl.c
  5. Abstract:
  6. This module contains the routines for to get Mdl for Reads and Writes
  7. directly from the Cache Mgr, which helps avoid one data copy and reduces
  8. our non-paged memory consumption (significantly!)
  9. Author:
  10. Shirish Koti
  11. Revision History:
  12. June 12, 1998 Initial Version
  13. Notes: Tab stop: 4
  14. --*/
  15. #define FILENUM FILE_CACHEMDL
  16. #include <afp.h>
  17. #include <forkio.h>
  18. #include <gendisp.h>
  19. VOID FASTCALL
  20. AfpAllocWriteMdl(
  21. IN PDELAYEDALLOC pDelAlloc
  22. )
  23. {
  24. PREQUEST pRequest;
  25. POPENFORKENTRY pOpenForkEntry;
  26. NTSTATUS status=STATUS_SUCCESS;
  27. ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
  28. ASSERT(VALID_SDA(pDelAlloc->pSda));
  29. ASSERT(pDelAlloc->BufSize >= CACHEMGR_WRITE_THRESHOLD);
  30. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_WRITE_MDL);
  31. pRequest = pDelAlloc->pRequest;
  32. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  33. ASSERT((VALID_OPENFORKENTRY(pOpenForkEntry)) || (pOpenForkEntry == NULL));
  34. // assume for now that cache mgr will fail to return the mdl
  35. status = STATUS_UNSUCCESSFUL;
  36. pRequest->rq_WriteMdl = NULL;
  37. if (pOpenForkEntry)
  38. {
  39. status = AfpBorrowWriteMdlFromCM(pDelAlloc, &pRequest->rq_WriteMdl);
  40. }
  41. if (status != STATUS_PENDING)
  42. {
  43. AfpAllocWriteMdlCompletion(NULL, NULL, pDelAlloc);
  44. }
  45. }
  46. NTSTATUS FASTCALL
  47. AfpBorrowWriteMdlFromCM(
  48. IN PDELAYEDALLOC pDelAlloc,
  49. OUT PMDL *ppReturnMdl
  50. )
  51. {
  52. IO_STATUS_BLOCK IoStsBlk;
  53. PIRP pIrp;
  54. PIO_STACK_LOCATION pIrpSp;
  55. PFAST_IO_DISPATCH pFastIoDisp;
  56. LARGE_INTEGER LargeOffset;
  57. BOOLEAN fGetMdlWorked;
  58. PSDA pSda;
  59. POPENFORKENTRY pOpenForkEntry;
  60. PFILE_OBJECT pFileObject;
  61. pSda = pDelAlloc->pSda;
  62. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  63. ASSERT(VALID_SDA(pSda));
  64. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  65. pFastIoDisp = pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
  66. pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
  67. ASSERT(pFileObject->Flags & FO_CACHE_SUPPORTED);
  68. ASSERT(pFastIoDisp->PrepareMdlWrite != NULL);
  69. LargeOffset = pDelAlloc->Offset;
  70. fGetMdlWorked = pFastIoDisp->PrepareMdlWrite(
  71. pFileObject,
  72. &LargeOffset,
  73. pDelAlloc->BufSize, // how big is the Write
  74. pSda->sda_SessionId,
  75. ppReturnMdl,
  76. &IoStsBlk,
  77. pOpenForkEntry->ofe_pDeviceObject);
  78. if (fGetMdlWorked && (*ppReturnMdl != NULL))
  79. {
  80. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO,
  81. ("AfpBorrowWriteMdlFromCM: fast path workd, Mdl = %lx\n",*ppReturnMdl));
  82. pDelAlloc->pMdl = *ppReturnMdl;
  83. return(STATUS_SUCCESS);
  84. }
  85. //
  86. // fast path didn't work (or worked only partially). We must give an irp down
  87. // to get the (rest of the) mdl
  88. //
  89. // Allocate and initialize the IRP for this operation.
  90. pIrp = AfpAllocIrp(pOpenForkEntry->ofe_pDeviceObject->StackSize);
  91. // yikes, how messy can it get!
  92. if (pIrp == NULL)
  93. {
  94. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  95. ("AfpBorrowWriteMdlFromCM: irp alloc failed!\n"));
  96. // if cache mgr returned a partial mdl, give it back!
  97. if (*ppReturnMdl)
  98. {
  99. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  100. ("AfpBorrowWriteMdlFromCM: giving back partial Mdl\n"));
  101. pDelAlloc->pMdl = *ppReturnMdl;
  102. pDelAlloc->Flags |= AFP_CACHEMDL_ALLOC_ERROR;
  103. pDelAlloc->pRequest->rq_CacheMgrContext = NULL;
  104. AfpReturnWriteMdlToCM(pDelAlloc);
  105. }
  106. return(STATUS_INSUFFICIENT_RESOURCES);
  107. }
  108. // Set up the completion routine.
  109. IoSetCompletionRoutine(
  110. pIrp,
  111. (PIO_COMPLETION_ROUTINE)AfpAllocWriteMdlCompletion,
  112. pDelAlloc,
  113. True,
  114. True,
  115. True);
  116. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  117. pIrp->Tail.Overlay.OriginalFileObject =
  118. AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
  119. pIrp->Tail.Overlay.Thread = AfpThread;
  120. pIrp->RequestorMode = KernelMode;
  121. pIrp->Flags = IRP_SYNCHRONOUS_API;
  122. pIrpSp->MajorFunction = IRP_MJ_WRITE;
  123. pIrpSp->MinorFunction = IRP_MN_MDL;
  124. pIrpSp->FileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
  125. pIrpSp->DeviceObject = pOpenForkEntry->ofe_pDeviceObject;
  126. pIrpSp->Parameters.Write.Length = pDelAlloc->BufSize;
  127. pIrpSp->Parameters.Write.Key = pSda->sda_SessionId;
  128. pIrpSp->Parameters.Write.ByteOffset = LargeOffset;
  129. //
  130. // *ppReturnMdl could potentially be non-null if the fast-path returned
  131. // a partial mdl
  132. //
  133. pIrp->MdlAddress = *ppReturnMdl;
  134. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_REQUESTED);
  135. AFP_DBG_SET_DELALLOC_IRP(pDelAlloc,pIrp);
  136. IoCallDriver(pOpenForkEntry->ofe_pDeviceObject, pIrp);
  137. return(STATUS_PENDING);
  138. }
  139. NTSTATUS
  140. AfpAllocWriteMdlCompletion(
  141. IN PDEVICE_OBJECT DeviceObject,
  142. IN PIRP pIrp,
  143. IN PVOID Context
  144. )
  145. {
  146. PSDA pSda;
  147. PBYTE pBuf;
  148. PREQUEST pRequest;
  149. PDELAYEDALLOC pDelAlloc;
  150. PMDL pMdl=NULL;
  151. NTSTATUS status=STATUS_SUCCESS;
  152. POPENFORKENTRY pOpenForkEntry;
  153. pDelAlloc = (PDELAYEDALLOC)Context;
  154. pSda = pDelAlloc->pSda;
  155. pRequest = pDelAlloc->pRequest;
  156. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  157. ASSERT(VALID_SDA(pSda));
  158. ASSERT(pDelAlloc->BufSize >= CACHEMGR_WRITE_THRESHOLD);
  159. ASSERT((VALID_OPENFORKENTRY(pOpenForkEntry)) || (pOpenForkEntry == NULL));
  160. if (pIrp)
  161. {
  162. status = pIrp->IoStatus.Status;
  163. //
  164. // mark the fact that this mdl belongs to the cache mgr
  165. //
  166. if (NT_SUCCESS(status))
  167. {
  168. pRequest->rq_WriteMdl = pIrp->MdlAddress;
  169. ASSERT(pRequest->rq_WriteMdl != NULL);
  170. pDelAlloc->pMdl = pRequest->rq_WriteMdl;
  171. }
  172. else
  173. {
  174. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  175. ("AfpAllocWriteMdlCompletion: irp %lx failed %lx\n",pIrp,status));
  176. ASSERT(pRequest->rq_WriteMdl == NULL);
  177. pRequest->rq_WriteMdl = NULL;
  178. }
  179. AfpFreeIrp(pIrp);
  180. AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, NULL);
  181. }
  182. //
  183. // if we didn't get Mdl from cache mgr, fall back to the old, traditional
  184. // way of allocating!
  185. //
  186. if (pRequest->rq_WriteMdl == NULL)
  187. {
  188. pBuf = AfpIOAllocBuffer(pDelAlloc->BufSize);
  189. if (pBuf != NULL)
  190. {
  191. pMdl = AfpAllocMdl(pBuf, pDelAlloc->BufSize, NULL);
  192. if (pMdl == NULL)
  193. {
  194. AfpIOFreeBuffer(pBuf);
  195. }
  196. }
  197. pRequest->rq_WriteMdl = pMdl;
  198. //
  199. // for whatever reason, we didn't get Mdl from cache mgr. Undo the
  200. // things we had done in preparation (NOTE: if we do get the Mdl from
  201. // cache mgr, we leave the refcount etc. in tact until the Mdl is actually
  202. // returned to cache mgr)
  203. //
  204. pRequest->rq_CacheMgrContext = NULL;
  205. // make sure we aren't forgetting cache mgr's mdl
  206. ASSERT(pDelAlloc->pMdl == NULL);
  207. // don't need that memory no more
  208. AfpFreeDelAlloc(pDelAlloc);
  209. AfpSdaDereferenceSession(pSda);
  210. if (pOpenForkEntry)
  211. {
  212. AfpForkDereference(pOpenForkEntry);
  213. }
  214. }
  215. else
  216. {
  217. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_IN_USE);
  218. AFP_DBG_INC_DELALLOC_BYTECOUNT(AfpWriteCMAlloced, pDelAlloc->BufSize);
  219. }
  220. //
  221. // tell the transport below to continue with the write
  222. //
  223. (*(pSda->sda_XportTable->asp_WriteContinue))(pRequest);
  224. return(STATUS_MORE_PROCESSING_REQUIRED);
  225. }
  226. VOID FASTCALL
  227. AfpReturnWriteMdlToCM(
  228. IN PDELAYEDALLOC pDelAlloc
  229. )
  230. {
  231. PDEVICE_OBJECT pDeviceObject;
  232. PFAST_IO_DISPATCH pFastIoDisp;
  233. PIRP pIrp;
  234. PIO_STACK_LOCATION pIrpSp;
  235. LARGE_INTEGER LargeOffset;
  236. PFILE_OBJECT pFileObject;
  237. PSDA pSda;
  238. POPENFORKENTRY pOpenForkEntry;
  239. PMDL pMdl;
  240. PVOID Context;
  241. ASSERT(pDelAlloc != NULL);
  242. ASSERT(pDelAlloc->pMdl != NULL);
  243. //
  244. // are we at DPC? if so, can't do this now
  245. //
  246. if (KeGetCurrentIrql() == DISPATCH_LEVEL)
  247. {
  248. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_QUEUED);
  249. AfpInitializeWorkItem(&pDelAlloc->WorkItem,
  250. AfpReturnWriteMdlToCM,
  251. pDelAlloc);
  252. AfpQueueWorkItem(&pDelAlloc->WorkItem);
  253. return;
  254. }
  255. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_IN_PROGRESS);
  256. pSda = pDelAlloc->pSda;
  257. pMdl = pDelAlloc->pMdl;
  258. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  259. ASSERT(VALID_SDA(pSda));
  260. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  261. pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject),
  262. pDeviceObject = pOpenForkEntry->ofe_pDeviceObject;
  263. LargeOffset = pDelAlloc->Offset;
  264. pFastIoDisp = pDeviceObject->DriverObject->FastIoDispatch;
  265. Context = pDelAlloc;
  266. //
  267. // if we came here because the cache mdl alloc failed but had partially
  268. // succeeded, then we don't want the completion routine to free up things
  269. // prematurely: in this case, pass NULL context
  270. //
  271. if (pDelAlloc->Flags & AFP_CACHEMDL_ALLOC_ERROR)
  272. {
  273. Context = NULL;
  274. }
  275. if (pFastIoDisp->MdlWriteComplete)
  276. {
  277. if (pFastIoDisp->MdlWriteComplete(
  278. pFileObject,
  279. &LargeOffset,
  280. pMdl,
  281. pDeviceObject) == TRUE)
  282. {
  283. AfpReturnWriteMdlToCMCompletion(NULL, NULL, Context);
  284. return;
  285. }
  286. }
  287. // Allocate and initialize the IRP for this operation.
  288. pIrp = AfpAllocIrp(pDeviceObject->StackSize);
  289. // yikes, how messy can it get!
  290. if (pIrp == NULL)
  291. {
  292. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  293. ("AfpReturnWriteMdlToCM: irp alloc failed!\n"));
  294. // log an event here - that's all we can do here!
  295. AFPLOG_ERROR(AFPSRVMSG_ALLOC_IRP, STATUS_INSUFFICIENT_RESOURCES,
  296. NULL, 0, NULL);
  297. AfpReturnWriteMdlToCMCompletion(NULL, NULL, Context);
  298. ASSERT(0);
  299. return;
  300. }
  301. // Set up the completion routine.
  302. IoSetCompletionRoutine(
  303. pIrp,
  304. (PIO_COMPLETION_ROUTINE)AfpReturnWriteMdlToCMCompletion,
  305. Context,
  306. True,
  307. True,
  308. True);
  309. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  310. pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pFileObject);
  311. pIrp->Tail.Overlay.Thread = AfpThread;
  312. pIrp->RequestorMode = KernelMode;
  313. pIrp->Flags = IRP_SYNCHRONOUS_API;
  314. pIrpSp->MajorFunction = IRP_MJ_WRITE;
  315. pIrpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE;
  316. pIrpSp->FileObject = AfpGetRealFileObject(pFileObject);
  317. pIrpSp->DeviceObject = pDeviceObject;
  318. pIrpSp->Parameters.Write.Length = pDelAlloc->BufSize;
  319. pIrpSp->Parameters.Write.ByteOffset = LargeOffset;
  320. pIrp->MdlAddress = pMdl;
  321. AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, pIrp);
  322. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_IN_PROGRESS);
  323. IoCallDriver(pDeviceObject, pIrp);
  324. }
  325. NTSTATUS
  326. AfpReturnWriteMdlToCMCompletion(
  327. IN PDEVICE_OBJECT DeviceObject,
  328. IN PIRP pIrp,
  329. IN PVOID Context
  330. )
  331. {
  332. PSDA pSda;
  333. PDELAYEDALLOC pDelAlloc;
  334. POPENFORKENTRY pOpenForkEntry;
  335. NTSTATUS status;
  336. AFPSTATUS AfpStatus=AFP_ERR_NONE;
  337. struct _ResponsePacket
  338. {
  339. BYTE __RealOffset[4];
  340. };
  341. pDelAlloc = (PDELAYEDALLOC)Context;
  342. if (pIrp)
  343. {
  344. status = pIrp->IoStatus.Status;
  345. //
  346. // mark the fact that this mdl belongs to the cache mgr
  347. //
  348. if (NT_SUCCESS(status))
  349. {
  350. AfpStatus = AFP_ERR_NONE;
  351. }
  352. else
  353. {
  354. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  355. ("AfpReturnWriteMdlToCMCompletion: irp failed %lx\n",status));
  356. ASSERT(0);
  357. AfpStatus = AFP_ERR_MISC;
  358. }
  359. AfpFreeIrp(pIrp);
  360. }
  361. //
  362. // if pDelAlloc is NULL, then some error occured while borrowing CM's mdl. We
  363. // We already finished up with the API at the time of the failure, so done here
  364. //
  365. if (pDelAlloc == NULL)
  366. {
  367. return(STATUS_MORE_PROCESSING_REQUIRED);
  368. }
  369. pSda = pDelAlloc->pSda;
  370. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  371. if (AfpStatus == AFP_ERR_NONE)
  372. {
  373. pSda->sda_ReplySize = SIZE_RESPPKT;
  374. if ((AfpStatus = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
  375. {
  376. PUTDWORD2DWORD(pRspPkt->__RealOffset,
  377. (pDelAlloc->Offset.LowPart + pDelAlloc->BufSize));
  378. }
  379. }
  380. else
  381. {
  382. pSda->sda_ReplySize = 0;
  383. }
  384. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_COMPLETED);
  385. AFP_DBG_DEC_DELALLOC_BYTECOUNT(AfpWriteCMAlloced, pDelAlloc->BufSize);
  386. //
  387. // call the completion routine only if everything is ok (we don't want
  388. // to call completion if session went dead)
  389. //
  390. if (!(pDelAlloc->Flags & AFP_CACHEMDL_DEADSESSION))
  391. {
  392. AfpCompleteApiProcessing(pSda, AfpStatus);
  393. }
  394. // remove the refcount when we referenced this
  395. AfpForkDereference(pOpenForkEntry);
  396. // remove the DelAlloc refcount
  397. AfpSdaDereferenceSession(pSda);
  398. // don't need that memory no more
  399. AfpFreeDelAlloc(pDelAlloc);
  400. return(STATUS_MORE_PROCESSING_REQUIRED);
  401. }
  402. NTSTATUS FASTCALL
  403. AfpBorrowReadMdlFromCM(
  404. IN PSDA pSda
  405. )
  406. {
  407. IO_STATUS_BLOCK IoStsBlk;
  408. PIRP pIrp;
  409. PIO_STACK_LOCATION pIrpSp;
  410. PFAST_IO_DISPATCH pFastIoDisp;
  411. PMDL pReturnMdl=NULL;
  412. KIRQL OldIrql;
  413. PREQUEST pRequest;
  414. PDELAYEDALLOC pDelAlloc;
  415. POPENFORKENTRY pOpenForkEntry;
  416. PFILE_OBJECT pFileObject;
  417. LARGE_INTEGER Offset;
  418. LARGE_INTEGER ReadSize;
  419. BOOLEAN fGetMdlWorked;
  420. struct _RequestPacket
  421. {
  422. POPENFORKENTRY _pOpenForkEntry;
  423. LONG _Offset;
  424. LONG _Size;
  425. DWORD _NlMask;
  426. DWORD _NlChar;
  427. };
  428. ASSERT(VALID_SDA(pSda));
  429. Offset.QuadPart = pReqPkt->_Offset;
  430. ReadSize.QuadPart = pReqPkt->_Size;
  431. pOpenForkEntry = pReqPkt->_pOpenForkEntry;
  432. pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
  433. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  434. pFastIoDisp = pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
  435. if (!(pFileObject->Flags & FO_CACHE_SUPPORTED))
  436. {
  437. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  438. ("AfpBorrowReadMdlFromCM: FO_CACHE_SUPPORTED not set\n"));
  439. return(STATUS_UNSUCCESSFUL);
  440. }
  441. if (pFastIoDisp->MdlRead == NULL)
  442. {
  443. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  444. ("AfpBorrowReadMdlFromCM: PrepareMdl is NULL\n"));
  445. return(STATUS_UNSUCCESSFUL);
  446. }
  447. pDelAlloc = AfpAllocDelAlloc();
  448. if (pDelAlloc == NULL)
  449. {
  450. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  451. ("AfpBorrowReadMdlFromCM: malloc for pDelAlloc failed\n"));
  452. return(STATUS_INSUFFICIENT_RESOURCES);
  453. }
  454. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_READ_MDL);
  455. // put DelAlloc refcount on pSda
  456. if (AfpSdaReferenceSessionByPointer(pSda) == NULL)
  457. {
  458. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  459. ("AfpBorrowReadMdlFromCM: couldn't reference pSda %lx\n",pSda));
  460. AfpFreeDelAlloc(pDelAlloc);
  461. return(STATUS_UNSUCCESSFUL);
  462. }
  463. // put DelAlloc refcount on pOpenForkEntry
  464. if (AfpForkReferenceByPointer(pOpenForkEntry) == NULL)
  465. {
  466. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  467. ("AfpBorrowReadMdlFromCM: couldn't reference %lx\n",pOpenForkEntry));
  468. // remove DelAlloc refcount
  469. AfpSdaDereferenceSession(pSda);
  470. AfpFreeDelAlloc(pDelAlloc);
  471. return(STATUS_UNSUCCESSFUL);
  472. }
  473. pRequest = pSda->sda_Request;
  474. ASSERT(pRequest->rq_ReplyMdl == NULL);
  475. pRequest->rq_CacheMgrContext = pDelAlloc;
  476. pDelAlloc->pSda = pSda;
  477. pDelAlloc->pRequest = pRequest;
  478. pDelAlloc->pOpenForkEntry = pOpenForkEntry;
  479. pDelAlloc->Offset = Offset;
  480. pDelAlloc->BufSize = ReadSize.LowPart;
  481. fGetMdlWorked = pFastIoDisp->MdlRead(
  482. pFileObject,
  483. &Offset,
  484. ReadSize.LowPart,
  485. pSda->sda_SessionId,
  486. &pReturnMdl,
  487. &IoStsBlk,
  488. pOpenForkEntry->ofe_pDeviceObject);
  489. if (fGetMdlWorked && (pReturnMdl != NULL))
  490. {
  491. pDelAlloc->pMdl = pReturnMdl;
  492. // call the completion routine, so the read can complete
  493. AfpBorrowReadMdlFromCMCompletion(NULL, NULL, pDelAlloc);
  494. return(STATUS_PENDING);
  495. }
  496. //
  497. // fast path didn't work (or worked only partially). We must give an irp down
  498. // to get the (rest of the) mdl
  499. //
  500. // Allocate and initialize the IRP for this operation.
  501. pIrp = AfpAllocIrp(pOpenForkEntry->ofe_pDeviceObject->StackSize);
  502. // yikes, how messy can it get!
  503. if (pIrp == NULL)
  504. {
  505. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  506. ("AfpBorrowReadMdlFromCM: irp alloc failed!\n"));
  507. // if cache mgr returned a partial mdl, give it back!
  508. if (pReturnMdl)
  509. {
  510. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  511. ("AfpBorrowReadMdlFromCM: giving back partial Mdl\n"));
  512. pDelAlloc->pMdl = pReturnMdl;
  513. pRequest->rq_CacheMgrContext = NULL;
  514. AfpReturnReadMdlToCM(pDelAlloc);
  515. }
  516. return(STATUS_INSUFFICIENT_RESOURCES);
  517. }
  518. // Set up the completion routine.
  519. IoSetCompletionRoutine(
  520. pIrp,
  521. (PIO_COMPLETION_ROUTINE)AfpBorrowReadMdlFromCMCompletion,
  522. pDelAlloc,
  523. True,
  524. True,
  525. True);
  526. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  527. pIrp->Tail.Overlay.OriginalFileObject =
  528. AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
  529. pIrp->Tail.Overlay.Thread = AfpThread;
  530. pIrp->RequestorMode = KernelMode;
  531. pIrp->Flags = IRP_SYNCHRONOUS_API;
  532. pIrpSp->MajorFunction = IRP_MJ_READ;
  533. pIrpSp->MinorFunction = IRP_MN_MDL;
  534. pIrpSp->FileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
  535. pIrpSp->DeviceObject = pOpenForkEntry->ofe_pDeviceObject;
  536. pIrpSp->Parameters.Write.Length = ReadSize.LowPart;
  537. pIrpSp->Parameters.Write.Key = pSda->sda_SessionId;
  538. pIrpSp->Parameters.Write.ByteOffset = Offset;
  539. //
  540. // pReturnMdl could potentially be non-null if the fast-path returned
  541. // a partial mdl
  542. //
  543. pIrp->MdlAddress = pReturnMdl;
  544. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_REQUESTED);
  545. AFP_DBG_SET_DELALLOC_IRP(pDelAlloc,pIrp);
  546. IoCallDriver(pOpenForkEntry->ofe_pDeviceObject, pIrp);
  547. return(STATUS_PENDING);
  548. }
  549. NTSTATUS
  550. AfpBorrowReadMdlFromCMCompletion(
  551. IN PDEVICE_OBJECT DeviceObject,
  552. IN PIRP pIrp,
  553. IN PVOID Context
  554. )
  555. {
  556. PSDA pSda;
  557. PREQUEST pRequest;
  558. PDELAYEDALLOC pDelAlloc;
  559. PMDL pMdl=NULL;
  560. NTSTATUS status=STATUS_SUCCESS;
  561. AFPSTATUS AfpStatus=AFP_ERR_NONE;
  562. PMDL pCurrMdl;
  563. DWORD CurrMdlSize;
  564. POPENFORKENTRY pOpenForkEntry;
  565. PBYTE pBuf;
  566. LONG iLoc;
  567. LONG i, Size;
  568. struct _RequestPacket
  569. {
  570. POPENFORKENTRY _pOpenForkEntry;
  571. LONG _Offset;
  572. LONG _Size;
  573. DWORD _NlMask;
  574. DWORD _NlChar;
  575. };
  576. pDelAlloc = (PDELAYEDALLOC)Context;
  577. pSda = pDelAlloc->pSda;
  578. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  579. pRequest = pDelAlloc->pRequest;
  580. ASSERT(VALID_SDA(pSda));
  581. ASSERT(pDelAlloc->BufSize >= CACHEMGR_READ_THRESHOLD);
  582. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  583. if (pIrp)
  584. {
  585. status = pIrp->IoStatus.Status;
  586. //
  587. // mark the fact that this mdl belongs to the cache mgr
  588. //
  589. if (NT_SUCCESS(status))
  590. {
  591. pDelAlloc->pMdl = pIrp->MdlAddress;
  592. ASSERT(pDelAlloc->pMdl != NULL);
  593. }
  594. else
  595. {
  596. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_WARN,
  597. ("AfpBorrowReadMdlFromCMCompletion: irp %lx failed %lx\n",pIrp,status));
  598. ASSERT(pDelAlloc->pMdl == NULL);
  599. pDelAlloc->pMdl = NULL;
  600. AfpStatus = AFP_ERR_MISC;
  601. }
  602. AfpFreeIrp(pIrp);
  603. AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, NULL);
  604. }
  605. pRequest->rq_ReplyMdl = pDelAlloc->pMdl;
  606. // did we get Mdl from the cache mgr? If so, we need to compute the reply size
  607. if (pRequest->rq_ReplyMdl != NULL)
  608. {
  609. Size = AfpMdlChainSize(pRequest->rq_ReplyMdl);
  610. if (Size == 0)
  611. {
  612. AfpStatus = AFP_ERR_EOF;
  613. }
  614. else if (pReqPkt->_NlMask != 0)
  615. {
  616. AfpStatus = AFP_ERR_NONE;
  617. pCurrMdl = pRequest->rq_ReplyMdl;
  618. CurrMdlSize = MmGetMdlByteCount(pCurrMdl);
  619. pBuf = MmGetSystemAddressForMdlSafe(
  620. pCurrMdl,
  621. NormalPagePriority);
  622. if (pBuf == NULL) {
  623. AfpStatus = AFP_ERR_MISC;
  624. goto error_end;
  625. }
  626. for (i=0, iLoc=0; i < Size; iLoc++, i++, pBuf++)
  627. {
  628. // move to the next Mdl if we exhausted this one
  629. if (iLoc >= (LONG)CurrMdlSize)
  630. {
  631. ASSERT(i < Size);
  632. pCurrMdl = pCurrMdl->Next;
  633. ASSERT(pCurrMdl != NULL);
  634. CurrMdlSize = MmGetMdlByteCount(pCurrMdl);
  635. pBuf = MmGetSystemAddressForMdlSafe(
  636. pCurrMdl,
  637. NormalPagePriority);
  638. if (pBuf == NULL) {
  639. AfpStatus = AFP_ERR_MISC;
  640. goto error_end;
  641. }
  642. iLoc = 0;
  643. }
  644. if ((*pBuf & (BYTE)(pReqPkt->_NlMask)) == (BYTE)(pReqPkt->_NlChar))
  645. {
  646. Size = ++i;
  647. break;
  648. }
  649. }
  650. }
  651. pSda->sda_ReplySize = (USHORT)Size;
  652. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_IN_USE);
  653. AFP_DBG_INC_DELALLOC_BYTECOUNT(AfpReadCMAlloced, pDelAlloc->BufSize);
  654. }
  655. //
  656. // we didn't get Mdl from cache mgr, fall back to the old, traditional
  657. // way of allocating and reading the file
  658. //
  659. else
  660. {
  661. // make sure we aren't forgetting cache mgr's mdl
  662. ASSERT(pDelAlloc->pMdl == NULL);
  663. pRequest->rq_CacheMgrContext = NULL;
  664. AfpForkDereference(pOpenForkEntry);
  665. AfpSdaDereferenceSession(pSda);
  666. // don't need that memory no more
  667. AfpFreeDelAlloc(pDelAlloc);
  668. AfpStatus = AfpFspDispReadContinue(pSda);
  669. }
  670. error_end:
  671. if (AfpStatus != AFP_ERR_EXTENDED)
  672. {
  673. AfpCompleteApiProcessing(pSda, AfpStatus);
  674. }
  675. return(STATUS_MORE_PROCESSING_REQUIRED);
  676. }
  677. VOID FASTCALL
  678. AfpReturnReadMdlToCM(
  679. IN PDELAYEDALLOC pDelAlloc
  680. )
  681. {
  682. PDEVICE_OBJECT pDeviceObject;
  683. PFAST_IO_DISPATCH pFastIoDisp;
  684. PIRP pIrp;
  685. PIO_STACK_LOCATION pIrpSp;
  686. LARGE_INTEGER LargeOffset;
  687. DWORD ReadSize;
  688. PFILE_OBJECT pFileObject;
  689. PSDA pSda;
  690. PMDL pMdl;
  691. POPENFORKENTRY pOpenForkEntry;
  692. ASSERT(pDelAlloc != NULL);
  693. ASSERT(pDelAlloc->pMdl != NULL);
  694. //
  695. // are we at DPC? if so, can't do this now
  696. //
  697. if (KeGetCurrentIrql() == DISPATCH_LEVEL)
  698. {
  699. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_QUEUED);
  700. AfpInitializeWorkItem(&pDelAlloc->WorkItem,
  701. AfpReturnReadMdlToCM,
  702. pDelAlloc);
  703. AfpQueueWorkItem(&pDelAlloc->WorkItem);
  704. return;
  705. }
  706. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_IN_PROGRESS);
  707. pSda = pDelAlloc->pSda;
  708. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  709. pMdl = pDelAlloc->pMdl;
  710. ASSERT(VALID_SDA(pSda));
  711. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  712. pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject),
  713. pDeviceObject = pOpenForkEntry->ofe_pDeviceObject;
  714. LargeOffset = pDelAlloc->Offset;
  715. ReadSize = pDelAlloc->BufSize;
  716. pFastIoDisp = pDeviceObject->DriverObject->FastIoDispatch;
  717. //
  718. // try the fast path to return the Mdl to cache mgr
  719. //
  720. if (pFastIoDisp->MdlReadComplete)
  721. {
  722. if (pFastIoDisp->MdlReadComplete(pFileObject,pMdl,pDeviceObject) == TRUE)
  723. {
  724. AfpReturnReadMdlToCMCompletion(NULL, NULL, pDelAlloc);
  725. return;
  726. }
  727. }
  728. //
  729. // hmmm: fast path didn't work, got to post an irp!
  730. //
  731. // Allocate and initialize the IRP for this operation.
  732. pIrp = AfpAllocIrp(pDeviceObject->StackSize);
  733. // yikes, how messy can it get!
  734. if (pIrp == NULL)
  735. {
  736. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  737. ("AfpReturnReadMdlToCM: irp alloc failed!\n"));
  738. // log an event here - that's all we can do here!
  739. AFPLOG_ERROR(AFPSRVMSG_ALLOC_IRP, STATUS_INSUFFICIENT_RESOURCES,
  740. NULL, 0, NULL);
  741. AfpReturnReadMdlToCMCompletion(NULL, NULL, pDelAlloc);
  742. ASSERT(0);
  743. return;
  744. }
  745. // Set up the completion routine.
  746. IoSetCompletionRoutine(
  747. pIrp,
  748. (PIO_COMPLETION_ROUTINE)AfpReturnReadMdlToCMCompletion,
  749. pDelAlloc,
  750. True,
  751. True,
  752. True);
  753. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  754. pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pFileObject);
  755. pIrp->Tail.Overlay.Thread = AfpThread;
  756. pIrp->RequestorMode = KernelMode;
  757. pIrp->Flags = IRP_SYNCHRONOUS_API;
  758. pIrpSp->MajorFunction = IRP_MJ_READ;
  759. pIrpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE;
  760. pIrpSp->FileObject = AfpGetRealFileObject(pFileObject);
  761. pIrpSp->DeviceObject = pDeviceObject;
  762. pIrpSp->Parameters.Read.ByteOffset = LargeOffset;
  763. pIrpSp->Parameters.Read.Length = ReadSize;
  764. pIrp->MdlAddress = pMdl;
  765. AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, pIrp);
  766. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_IN_PROGRESS);
  767. IoCallDriver(pDeviceObject, pIrp);
  768. }
  769. NTSTATUS
  770. AfpReturnReadMdlToCMCompletion(
  771. IN PDEVICE_OBJECT DeviceObject,
  772. IN PIRP pIrp,
  773. IN PVOID Context
  774. )
  775. {
  776. PDELAYEDALLOC pDelAlloc;
  777. PSDA pSda;
  778. POPENFORKENTRY pOpenForkEntry;
  779. NTSTATUS status;
  780. pDelAlloc = (PDELAYEDALLOC)Context;
  781. ASSERT(pDelAlloc != NULL);
  782. pSda = pDelAlloc->pSda;
  783. pOpenForkEntry = pDelAlloc->pOpenForkEntry;
  784. ASSERT(VALID_SDA(pSda));
  785. ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
  786. if (pIrp)
  787. {
  788. status = pIrp->IoStatus.Status;
  789. if (!NT_SUCCESS(status))
  790. {
  791. DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR,
  792. ("AfpReturnReadMdlToCMCompletion: irp failed %lx\n",status));
  793. ASSERT(0);
  794. }
  795. AfpFreeIrp(pIrp);
  796. }
  797. AfpForkDereference(pOpenForkEntry);
  798. AfpSdaDereferenceSession(pSda);
  799. AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_COMPLETED);
  800. AFP_DBG_DEC_DELALLOC_BYTECOUNT(AfpReadCMAlloced, pDelAlloc->BufSize);
  801. // don't need that memory no more
  802. AfpFreeDelAlloc(pDelAlloc);
  803. return(STATUS_MORE_PROCESSING_REQUIRED);
  804. }
  805. PDELAYEDALLOC FASTCALL
  806. AfpAllocDelAlloc(
  807. IN VOID
  808. )
  809. {
  810. PDELAYEDALLOC pDelAlloc;
  811. KIRQL OldIrql;
  812. pDelAlloc = (PDELAYEDALLOC) AfpAllocZeroedNonPagedMemory(sizeof(DELAYEDALLOC));
  813. #if DBG
  814. if (pDelAlloc)
  815. {
  816. pDelAlloc->Signature = AFP_DELALLOC_SIGNATURE;
  817. pDelAlloc->State = AFP_DBG_MDL_INIT;
  818. ACQUIRE_SPIN_LOCK(&AfpDebugSpinLock, &OldIrql);
  819. InsertTailList(&AfpDebugDelAllocHead, &pDelAlloc->Linkage);
  820. RELEASE_SPIN_LOCK(&AfpDebugSpinLock, OldIrql);
  821. }
  822. #endif
  823. return(pDelAlloc);
  824. }
  825. VOID FASTCALL
  826. AfpFreeDelAlloc(
  827. IN PDELAYEDALLOC pDelAlloc
  828. )
  829. {
  830. KIRQL OldIrql;
  831. #if DBG
  832. ASSERT(pDelAlloc->Signature == AFP_DELALLOC_SIGNATURE);
  833. pDelAlloc->State |= AFP_DBG_MDL_END;
  834. ACQUIRE_SPIN_LOCK(&AfpDebugSpinLock, &OldIrql);
  835. RemoveEntryList(&pDelAlloc->Linkage);
  836. pDelAlloc->Linkage.Flink = (PLIST_ENTRY)0x11111111;
  837. pDelAlloc->Linkage.Blink = (PLIST_ENTRY)0x33333333;
  838. RELEASE_SPIN_LOCK(&AfpDebugSpinLock, OldIrql);
  839. #endif
  840. AfpFreeMemory(pDelAlloc);
  841. }