|
|
/*
Copyright (c) 1992 Microsoft Corporation
Module Name:
cachemdl.c
Abstract:
This module contains the routines for to get Mdl for Reads and Writes directly from the Cache Mgr, which helps avoid one data copy and reduces our non-paged memory consumption (significantly!)
Author:
Shirish Koti
Revision History: June 12, 1998 Initial Version
Notes: Tab stop: 4 --*/
#define FILENUM FILE_CACHEMDL
#include <afp.h>
#include <forkio.h>
#include <gendisp.h>
VOID FASTCALL AfpAllocWriteMdl( IN PDELAYEDALLOC pDelAlloc ) { PREQUEST pRequest; POPENFORKENTRY pOpenForkEntry; NTSTATUS status=STATUS_SUCCESS;
ASSERT(KeGetCurrentIrql() == LOW_LEVEL); ASSERT(VALID_SDA(pDelAlloc->pSda)); ASSERT(pDelAlloc->BufSize >= CACHEMGR_WRITE_THRESHOLD);
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_WRITE_MDL);
pRequest = pDelAlloc->pRequest; pOpenForkEntry = pDelAlloc->pOpenForkEntry;
ASSERT((VALID_OPENFORKENTRY(pOpenForkEntry)) || (pOpenForkEntry == NULL));
// assume for now that cache mgr will fail to return the mdl
status = STATUS_UNSUCCESSFUL; pRequest->rq_WriteMdl = NULL;
if (pOpenForkEntry) { status = AfpBorrowWriteMdlFromCM(pDelAlloc, &pRequest->rq_WriteMdl); }
if (status != STATUS_PENDING) { AfpAllocWriteMdlCompletion(NULL, NULL, pDelAlloc); } }
NTSTATUS FASTCALL AfpBorrowWriteMdlFromCM( IN PDELAYEDALLOC pDelAlloc, OUT PMDL *ppReturnMdl ) {
IO_STATUS_BLOCK IoStsBlk; PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PFAST_IO_DISPATCH pFastIoDisp; LARGE_INTEGER LargeOffset; BOOLEAN fGetMdlWorked; PSDA pSda; POPENFORKENTRY pOpenForkEntry; PFILE_OBJECT pFileObject;
pSda = pDelAlloc->pSda; pOpenForkEntry = pDelAlloc->pOpenForkEntry;
ASSERT(VALID_SDA(pSda)); ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
pFastIoDisp = pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
ASSERT(pFileObject->Flags & FO_CACHE_SUPPORTED);
ASSERT(pFastIoDisp->PrepareMdlWrite != NULL);
LargeOffset = pDelAlloc->Offset;
fGetMdlWorked = pFastIoDisp->PrepareMdlWrite( pFileObject, &LargeOffset, pDelAlloc->BufSize, // how big is the Write
pSda->sda_SessionId, ppReturnMdl, &IoStsBlk, pOpenForkEntry->ofe_pDeviceObject);
if (fGetMdlWorked && (*ppReturnMdl != NULL)) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_INFO, ("AfpBorrowWriteMdlFromCM: fast path workd, Mdl = %lx\n",*ppReturnMdl));
pDelAlloc->pMdl = *ppReturnMdl;
return(STATUS_SUCCESS); }
//
// fast path didn't work (or worked only partially). We must give an irp down
// to get the (rest of the) mdl
//
// Allocate and initialize the IRP for this operation.
pIrp = AfpAllocIrp(pOpenForkEntry->ofe_pDeviceObject->StackSize);
// yikes, how messy can it get!
if (pIrp == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowWriteMdlFromCM: irp alloc failed!\n"));
// if cache mgr returned a partial mdl, give it back!
if (*ppReturnMdl) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowWriteMdlFromCM: giving back partial Mdl\n"));
pDelAlloc->pMdl = *ppReturnMdl; pDelAlloc->Flags |= AFP_CACHEMDL_ALLOC_ERROR;
pDelAlloc->pRequest->rq_CacheMgrContext = NULL;
AfpReturnWriteMdlToCM(pDelAlloc); } return(STATUS_INSUFFICIENT_RESOURCES); }
// Set up the completion routine.
IoSetCompletionRoutine( pIrp, (PIO_COMPLETION_ROUTINE)AfpAllocWriteMdlCompletion, pDelAlloc, True, True, True);
pIrpSp = IoGetNextIrpStackLocation(pIrp);
pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject); pIrp->Tail.Overlay.Thread = AfpThread; pIrp->RequestorMode = KernelMode;
pIrp->Flags = IRP_SYNCHRONOUS_API;
pIrpSp->MajorFunction = IRP_MJ_WRITE; pIrpSp->MinorFunction = IRP_MN_MDL; pIrpSp->FileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject); pIrpSp->DeviceObject = pOpenForkEntry->ofe_pDeviceObject;
pIrpSp->Parameters.Write.Length = pDelAlloc->BufSize; pIrpSp->Parameters.Write.Key = pSda->sda_SessionId; pIrpSp->Parameters.Write.ByteOffset = LargeOffset;
//
// *ppReturnMdl could potentially be non-null if the fast-path returned
// a partial mdl
//
pIrp->MdlAddress = *ppReturnMdl;
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_REQUESTED); AFP_DBG_SET_DELALLOC_IRP(pDelAlloc,pIrp);
IoCallDriver(pOpenForkEntry->ofe_pDeviceObject, pIrp);
return(STATUS_PENDING); }
NTSTATUS AfpAllocWriteMdlCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context ) { PSDA pSda; PBYTE pBuf; PREQUEST pRequest; PDELAYEDALLOC pDelAlloc; PMDL pMdl=NULL; NTSTATUS status=STATUS_SUCCESS; POPENFORKENTRY pOpenForkEntry;
pDelAlloc = (PDELAYEDALLOC)Context;
pSda = pDelAlloc->pSda; pRequest = pDelAlloc->pRequest; pOpenForkEntry = pDelAlloc->pOpenForkEntry;
ASSERT(VALID_SDA(pSda)); ASSERT(pDelAlloc->BufSize >= CACHEMGR_WRITE_THRESHOLD); ASSERT((VALID_OPENFORKENTRY(pOpenForkEntry)) || (pOpenForkEntry == NULL));
if (pIrp) { status = pIrp->IoStatus.Status;
//
// mark the fact that this mdl belongs to the cache mgr
//
if (NT_SUCCESS(status)) { pRequest->rq_WriteMdl = pIrp->MdlAddress; ASSERT(pRequest->rq_WriteMdl != NULL);
pDelAlloc->pMdl = pRequest->rq_WriteMdl; } else { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpAllocWriteMdlCompletion: irp %lx failed %lx\n",pIrp,status));
ASSERT(pRequest->rq_WriteMdl == NULL); pRequest->rq_WriteMdl = NULL; }
AfpFreeIrp(pIrp);
AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, NULL); }
//
// if we didn't get Mdl from cache mgr, fall back to the old, traditional
// way of allocating!
//
if (pRequest->rq_WriteMdl == NULL) { pBuf = AfpIOAllocBuffer(pDelAlloc->BufSize);
if (pBuf != NULL) { pMdl = AfpAllocMdl(pBuf, pDelAlloc->BufSize, NULL); if (pMdl == NULL) { AfpIOFreeBuffer(pBuf); } }
pRequest->rq_WriteMdl = pMdl;
//
// for whatever reason, we didn't get Mdl from cache mgr. Undo the
// things we had done in preparation (NOTE: if we do get the Mdl from
// cache mgr, we leave the refcount etc. in tact until the Mdl is actually
// returned to cache mgr)
//
pRequest->rq_CacheMgrContext = NULL;
// make sure we aren't forgetting cache mgr's mdl
ASSERT(pDelAlloc->pMdl == NULL);
// don't need that memory no more
AfpFreeDelAlloc(pDelAlloc);
AfpSdaDereferenceSession(pSda);
if (pOpenForkEntry) { AfpForkDereference(pOpenForkEntry); } } else { AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_IN_USE); AFP_DBG_INC_DELALLOC_BYTECOUNT(AfpWriteCMAlloced, pDelAlloc->BufSize); }
//
// tell the transport below to continue with the write
//
(*(pSda->sda_XportTable->asp_WriteContinue))(pRequest);
return(STATUS_MORE_PROCESSING_REQUIRED); }
VOID FASTCALL AfpReturnWriteMdlToCM( IN PDELAYEDALLOC pDelAlloc ) { PDEVICE_OBJECT pDeviceObject; PFAST_IO_DISPATCH pFastIoDisp; PIRP pIrp; PIO_STACK_LOCATION pIrpSp; LARGE_INTEGER LargeOffset; PFILE_OBJECT pFileObject; PSDA pSda; POPENFORKENTRY pOpenForkEntry; PMDL pMdl; PVOID Context;
ASSERT(pDelAlloc != NULL); ASSERT(pDelAlloc->pMdl != NULL);
//
// are we at DPC? if so, can't do this now
//
if (KeGetCurrentIrql() == DISPATCH_LEVEL) { AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_QUEUED);
AfpInitializeWorkItem(&pDelAlloc->WorkItem, AfpReturnWriteMdlToCM, pDelAlloc);
AfpQueueWorkItem(&pDelAlloc->WorkItem); return; }
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_IN_PROGRESS);
pSda = pDelAlloc->pSda; pMdl = pDelAlloc->pMdl; pOpenForkEntry = pDelAlloc->pOpenForkEntry;
ASSERT(VALID_SDA(pSda)); ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject), pDeviceObject = pOpenForkEntry->ofe_pDeviceObject;
LargeOffset = pDelAlloc->Offset;
pFastIoDisp = pDeviceObject->DriverObject->FastIoDispatch;
Context = pDelAlloc;
//
// if we came here because the cache mdl alloc failed but had partially
// succeeded, then we don't want the completion routine to free up things
// prematurely: in this case, pass NULL context
//
if (pDelAlloc->Flags & AFP_CACHEMDL_ALLOC_ERROR) { Context = NULL; }
if (pFastIoDisp->MdlWriteComplete) { if (pFastIoDisp->MdlWriteComplete( pFileObject, &LargeOffset, pMdl, pDeviceObject) == TRUE) { AfpReturnWriteMdlToCMCompletion(NULL, NULL, Context); return; } }
// Allocate and initialize the IRP for this operation.
pIrp = AfpAllocIrp(pDeviceObject->StackSize);
// yikes, how messy can it get!
if (pIrp == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpReturnWriteMdlToCM: irp alloc failed!\n"));
// log an event here - that's all we can do here!
AFPLOG_ERROR(AFPSRVMSG_ALLOC_IRP, STATUS_INSUFFICIENT_RESOURCES, NULL, 0, NULL); AfpReturnWriteMdlToCMCompletion(NULL, NULL, Context);
ASSERT(0); return; }
// Set up the completion routine.
IoSetCompletionRoutine( pIrp, (PIO_COMPLETION_ROUTINE)AfpReturnWriteMdlToCMCompletion, Context, True, True, True);
pIrpSp = IoGetNextIrpStackLocation(pIrp);
pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pFileObject); pIrp->Tail.Overlay.Thread = AfpThread; pIrp->RequestorMode = KernelMode;
pIrp->Flags = IRP_SYNCHRONOUS_API;
pIrpSp->MajorFunction = IRP_MJ_WRITE; pIrpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE; pIrpSp->FileObject = AfpGetRealFileObject(pFileObject); pIrpSp->DeviceObject = pDeviceObject;
pIrpSp->Parameters.Write.Length = pDelAlloc->BufSize;
pIrpSp->Parameters.Write.ByteOffset = LargeOffset;
pIrp->MdlAddress = pMdl;
AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, pIrp); AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_IN_PROGRESS);
IoCallDriver(pDeviceObject, pIrp);
}
NTSTATUS AfpReturnWriteMdlToCMCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context ) { PSDA pSda; PDELAYEDALLOC pDelAlloc; POPENFORKENTRY pOpenForkEntry; NTSTATUS status; AFPSTATUS AfpStatus=AFP_ERR_NONE;
struct _ResponsePacket { BYTE __RealOffset[4]; };
pDelAlloc = (PDELAYEDALLOC)Context;
if (pIrp) { status = pIrp->IoStatus.Status;
//
// mark the fact that this mdl belongs to the cache mgr
//
if (NT_SUCCESS(status)) {
AfpStatus = AFP_ERR_NONE; } else { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpReturnWriteMdlToCMCompletion: irp failed %lx\n",status));
ASSERT(0); AfpStatus = AFP_ERR_MISC; }
AfpFreeIrp(pIrp); }
//
// if pDelAlloc is NULL, then some error occured while borrowing CM's mdl. We
// We already finished up with the API at the time of the failure, so done here
//
if (pDelAlloc == NULL) { return(STATUS_MORE_PROCESSING_REQUIRED); }
pSda = pDelAlloc->pSda; pOpenForkEntry = pDelAlloc->pOpenForkEntry;
if (AfpStatus == AFP_ERR_NONE) { pSda->sda_ReplySize = SIZE_RESPPKT; if ((AfpStatus = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE) { PUTDWORD2DWORD(pRspPkt->__RealOffset, (pDelAlloc->Offset.LowPart + pDelAlloc->BufSize)); } } else { pSda->sda_ReplySize = 0; }
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_COMPLETED); AFP_DBG_DEC_DELALLOC_BYTECOUNT(AfpWriteCMAlloced, pDelAlloc->BufSize);
//
// call the completion routine only if everything is ok (we don't want
// to call completion if session went dead)
//
if (!(pDelAlloc->Flags & AFP_CACHEMDL_DEADSESSION)) { AfpCompleteApiProcessing(pSda, AfpStatus); }
// remove the refcount when we referenced this
AfpForkDereference(pOpenForkEntry);
// remove the DelAlloc refcount
AfpSdaDereferenceSession(pSda);
// don't need that memory no more
AfpFreeDelAlloc(pDelAlloc);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
NTSTATUS FASTCALL AfpBorrowReadMdlFromCM( IN PSDA pSda ) {
IO_STATUS_BLOCK IoStsBlk; PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PFAST_IO_DISPATCH pFastIoDisp; PMDL pReturnMdl=NULL; KIRQL OldIrql; PREQUEST pRequest; PDELAYEDALLOC pDelAlloc; POPENFORKENTRY pOpenForkEntry; PFILE_OBJECT pFileObject; LARGE_INTEGER Offset; LARGE_INTEGER ReadSize; BOOLEAN fGetMdlWorked; struct _RequestPacket { POPENFORKENTRY _pOpenForkEntry; LONG _Offset; LONG _Size; DWORD _NlMask; DWORD _NlChar; };
ASSERT(VALID_SDA(pSda));
Offset.QuadPart = pReqPkt->_Offset; ReadSize.QuadPart = pReqPkt->_Size;
pOpenForkEntry = pReqPkt->_pOpenForkEntry;
pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
pFastIoDisp = pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
if (!(pFileObject->Flags & FO_CACHE_SUPPORTED)) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowReadMdlFromCM: FO_CACHE_SUPPORTED not set\n"));
return(STATUS_UNSUCCESSFUL); }
if (pFastIoDisp->MdlRead == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowReadMdlFromCM: PrepareMdl is NULL\n"));
return(STATUS_UNSUCCESSFUL); }
pDelAlloc = AfpAllocDelAlloc();
if (pDelAlloc == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowReadMdlFromCM: malloc for pDelAlloc failed\n"));
return(STATUS_INSUFFICIENT_RESOURCES); }
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_READ_MDL);
// put DelAlloc refcount on pSda
if (AfpSdaReferenceSessionByPointer(pSda) == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowReadMdlFromCM: couldn't reference pSda %lx\n",pSda));
AfpFreeDelAlloc(pDelAlloc); return(STATUS_UNSUCCESSFUL); }
// put DelAlloc refcount on pOpenForkEntry
if (AfpForkReferenceByPointer(pOpenForkEntry) == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowReadMdlFromCM: couldn't reference %lx\n",pOpenForkEntry));
// remove DelAlloc refcount
AfpSdaDereferenceSession(pSda); AfpFreeDelAlloc(pDelAlloc); return(STATUS_UNSUCCESSFUL); }
pRequest = pSda->sda_Request;
ASSERT(pRequest->rq_ReplyMdl == NULL);
pRequest->rq_CacheMgrContext = pDelAlloc;
pDelAlloc->pSda = pSda; pDelAlloc->pRequest = pRequest; pDelAlloc->pOpenForkEntry = pOpenForkEntry; pDelAlloc->Offset = Offset; pDelAlloc->BufSize = ReadSize.LowPart;
fGetMdlWorked = pFastIoDisp->MdlRead( pFileObject, &Offset, ReadSize.LowPart, pSda->sda_SessionId, &pReturnMdl, &IoStsBlk, pOpenForkEntry->ofe_pDeviceObject);
if (fGetMdlWorked && (pReturnMdl != NULL)) { pDelAlloc->pMdl = pReturnMdl;
// call the completion routine, so the read can complete
AfpBorrowReadMdlFromCMCompletion(NULL, NULL, pDelAlloc);
return(STATUS_PENDING); }
//
// fast path didn't work (or worked only partially). We must give an irp down
// to get the (rest of the) mdl
//
// Allocate and initialize the IRP for this operation.
pIrp = AfpAllocIrp(pOpenForkEntry->ofe_pDeviceObject->StackSize);
// yikes, how messy can it get!
if (pIrp == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowReadMdlFromCM: irp alloc failed!\n"));
// if cache mgr returned a partial mdl, give it back!
if (pReturnMdl) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpBorrowReadMdlFromCM: giving back partial Mdl\n"));
pDelAlloc->pMdl = pReturnMdl; pRequest->rq_CacheMgrContext = NULL;
AfpReturnReadMdlToCM(pDelAlloc); } return(STATUS_INSUFFICIENT_RESOURCES); }
// Set up the completion routine.
IoSetCompletionRoutine( pIrp, (PIO_COMPLETION_ROUTINE)AfpBorrowReadMdlFromCMCompletion, pDelAlloc, True, True, True);
pIrpSp = IoGetNextIrpStackLocation(pIrp);
pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject); pIrp->Tail.Overlay.Thread = AfpThread; pIrp->RequestorMode = KernelMode;
pIrp->Flags = IRP_SYNCHRONOUS_API;
pIrpSp->MajorFunction = IRP_MJ_READ; pIrpSp->MinorFunction = IRP_MN_MDL; pIrpSp->FileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject); pIrpSp->DeviceObject = pOpenForkEntry->ofe_pDeviceObject;
pIrpSp->Parameters.Write.Length = ReadSize.LowPart; pIrpSp->Parameters.Write.Key = pSda->sda_SessionId; pIrpSp->Parameters.Write.ByteOffset = Offset;
//
// pReturnMdl could potentially be non-null if the fast-path returned
// a partial mdl
//
pIrp->MdlAddress = pReturnMdl;
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_REQUESTED); AFP_DBG_SET_DELALLOC_IRP(pDelAlloc,pIrp);
IoCallDriver(pOpenForkEntry->ofe_pDeviceObject, pIrp);
return(STATUS_PENDING); }
NTSTATUS AfpBorrowReadMdlFromCMCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context ) {
PSDA pSda; PREQUEST pRequest; PDELAYEDALLOC pDelAlloc; PMDL pMdl=NULL; NTSTATUS status=STATUS_SUCCESS; AFPSTATUS AfpStatus=AFP_ERR_NONE; PMDL pCurrMdl; DWORD CurrMdlSize; POPENFORKENTRY pOpenForkEntry; PBYTE pBuf; LONG iLoc; LONG i, Size; struct _RequestPacket { POPENFORKENTRY _pOpenForkEntry; LONG _Offset; LONG _Size; DWORD _NlMask; DWORD _NlChar; };
pDelAlloc = (PDELAYEDALLOC)Context;
pSda = pDelAlloc->pSda; pOpenForkEntry = pDelAlloc->pOpenForkEntry; pRequest = pDelAlloc->pRequest;
ASSERT(VALID_SDA(pSda)); ASSERT(pDelAlloc->BufSize >= CACHEMGR_READ_THRESHOLD); ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
if (pIrp) { status = pIrp->IoStatus.Status;
//
// mark the fact that this mdl belongs to the cache mgr
//
if (NT_SUCCESS(status)) { pDelAlloc->pMdl = pIrp->MdlAddress;
ASSERT(pDelAlloc->pMdl != NULL); } else { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_WARN, ("AfpBorrowReadMdlFromCMCompletion: irp %lx failed %lx\n",pIrp,status));
ASSERT(pDelAlloc->pMdl == NULL); pDelAlloc->pMdl = NULL;
AfpStatus = AFP_ERR_MISC; }
AfpFreeIrp(pIrp);
AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, NULL); }
pRequest->rq_ReplyMdl = pDelAlloc->pMdl;
// did we get Mdl from the cache mgr? If so, we need to compute the reply size
if (pRequest->rq_ReplyMdl != NULL) { Size = AfpMdlChainSize(pRequest->rq_ReplyMdl);
if (Size == 0) { AfpStatus = AFP_ERR_EOF; } else if (pReqPkt->_NlMask != 0) { AfpStatus = AFP_ERR_NONE;
pCurrMdl = pRequest->rq_ReplyMdl;
CurrMdlSize = MmGetMdlByteCount(pCurrMdl); pBuf = MmGetSystemAddressForMdlSafe( pCurrMdl, NormalPagePriority);
if (pBuf == NULL) { AfpStatus = AFP_ERR_MISC; goto error_end; }
for (i=0, iLoc=0; i < Size; iLoc++, i++, pBuf++) { // move to the next Mdl if we exhausted this one
if (iLoc >= (LONG)CurrMdlSize) { ASSERT(i < Size);
pCurrMdl = pCurrMdl->Next; ASSERT(pCurrMdl != NULL);
CurrMdlSize = MmGetMdlByteCount(pCurrMdl); pBuf = MmGetSystemAddressForMdlSafe( pCurrMdl, NormalPagePriority); if (pBuf == NULL) { AfpStatus = AFP_ERR_MISC; goto error_end; }
iLoc = 0; }
if ((*pBuf & (BYTE)(pReqPkt->_NlMask)) == (BYTE)(pReqPkt->_NlChar)) { Size = ++i; break; } } }
pSda->sda_ReplySize = (USHORT)Size;
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_IN_USE); AFP_DBG_INC_DELALLOC_BYTECOUNT(AfpReadCMAlloced, pDelAlloc->BufSize); }
//
// we didn't get Mdl from cache mgr, fall back to the old, traditional
// way of allocating and reading the file
//
else { // make sure we aren't forgetting cache mgr's mdl
ASSERT(pDelAlloc->pMdl == NULL);
pRequest->rq_CacheMgrContext = NULL;
AfpForkDereference(pOpenForkEntry);
AfpSdaDereferenceSession(pSda);
// don't need that memory no more
AfpFreeDelAlloc(pDelAlloc);
AfpStatus = AfpFspDispReadContinue(pSda); }
error_end: if (AfpStatus != AFP_ERR_EXTENDED) { AfpCompleteApiProcessing(pSda, AfpStatus); }
return(STATUS_MORE_PROCESSING_REQUIRED);
}
VOID FASTCALL AfpReturnReadMdlToCM( IN PDELAYEDALLOC pDelAlloc ) { PDEVICE_OBJECT pDeviceObject; PFAST_IO_DISPATCH pFastIoDisp; PIRP pIrp; PIO_STACK_LOCATION pIrpSp; LARGE_INTEGER LargeOffset; DWORD ReadSize; PFILE_OBJECT pFileObject; PSDA pSda; PMDL pMdl; POPENFORKENTRY pOpenForkEntry;
ASSERT(pDelAlloc != NULL); ASSERT(pDelAlloc->pMdl != NULL);
//
// are we at DPC? if so, can't do this now
//
if (KeGetCurrentIrql() == DISPATCH_LEVEL) { AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_QUEUED);
AfpInitializeWorkItem(&pDelAlloc->WorkItem, AfpReturnReadMdlToCM, pDelAlloc); AfpQueueWorkItem(&pDelAlloc->WorkItem); return; }
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_PROC_IN_PROGRESS);
pSda = pDelAlloc->pSda; pOpenForkEntry = pDelAlloc->pOpenForkEntry;
pMdl = pDelAlloc->pMdl;
ASSERT(VALID_SDA(pSda)); ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
pFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject), pDeviceObject = pOpenForkEntry->ofe_pDeviceObject;
LargeOffset = pDelAlloc->Offset; ReadSize = pDelAlloc->BufSize;
pFastIoDisp = pDeviceObject->DriverObject->FastIoDispatch;
//
// try the fast path to return the Mdl to cache mgr
//
if (pFastIoDisp->MdlReadComplete) { if (pFastIoDisp->MdlReadComplete(pFileObject,pMdl,pDeviceObject) == TRUE) { AfpReturnReadMdlToCMCompletion(NULL, NULL, pDelAlloc); return; } }
//
// hmmm: fast path didn't work, got to post an irp!
//
// Allocate and initialize the IRP for this operation.
pIrp = AfpAllocIrp(pDeviceObject->StackSize);
// yikes, how messy can it get!
if (pIrp == NULL) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpReturnReadMdlToCM: irp alloc failed!\n"));
// log an event here - that's all we can do here!
AFPLOG_ERROR(AFPSRVMSG_ALLOC_IRP, STATUS_INSUFFICIENT_RESOURCES, NULL, 0, NULL);
AfpReturnReadMdlToCMCompletion(NULL, NULL, pDelAlloc);
ASSERT(0); return; }
// Set up the completion routine.
IoSetCompletionRoutine( pIrp, (PIO_COMPLETION_ROUTINE)AfpReturnReadMdlToCMCompletion, pDelAlloc, True, True, True);
pIrpSp = IoGetNextIrpStackLocation(pIrp);
pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pFileObject); pIrp->Tail.Overlay.Thread = AfpThread; pIrp->RequestorMode = KernelMode;
pIrp->Flags = IRP_SYNCHRONOUS_API;
pIrpSp->MajorFunction = IRP_MJ_READ; pIrpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE; pIrpSp->FileObject = AfpGetRealFileObject(pFileObject); pIrpSp->DeviceObject = pDeviceObject;
pIrpSp->Parameters.Read.ByteOffset = LargeOffset; pIrpSp->Parameters.Read.Length = ReadSize;
pIrp->MdlAddress = pMdl;
AFP_DBG_SET_DELALLOC_IRP(pDelAlloc, pIrp); AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_IN_PROGRESS);
IoCallDriver(pDeviceObject, pIrp);
}
NTSTATUS AfpReturnReadMdlToCMCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context ) { PDELAYEDALLOC pDelAlloc; PSDA pSda; POPENFORKENTRY pOpenForkEntry; NTSTATUS status;
pDelAlloc = (PDELAYEDALLOC)Context;
ASSERT(pDelAlloc != NULL);
pSda = pDelAlloc->pSda; pOpenForkEntry = pDelAlloc->pOpenForkEntry;
ASSERT(VALID_SDA(pSda)); ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
if (pIrp) { status = pIrp->IoStatus.Status;
if (!NT_SUCCESS(status)) { DBGPRINT(DBG_COMP_AFPAPI, DBG_LEVEL_ERR, ("AfpReturnReadMdlToCMCompletion: irp failed %lx\n",status));
ASSERT(0); }
AfpFreeIrp(pIrp); }
AfpForkDereference(pOpenForkEntry);
AfpSdaDereferenceSession(pSda);
AFP_DBG_SET_DELALLOC_STATE(pDelAlloc, AFP_DBG_MDL_RETURN_COMPLETED); AFP_DBG_DEC_DELALLOC_BYTECOUNT(AfpReadCMAlloced, pDelAlloc->BufSize);
// don't need that memory no more
AfpFreeDelAlloc(pDelAlloc);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
PDELAYEDALLOC FASTCALL AfpAllocDelAlloc( IN VOID ) { PDELAYEDALLOC pDelAlloc; KIRQL OldIrql;
pDelAlloc = (PDELAYEDALLOC) AfpAllocZeroedNonPagedMemory(sizeof(DELAYEDALLOC));
#if DBG
if (pDelAlloc) { pDelAlloc->Signature = AFP_DELALLOC_SIGNATURE; pDelAlloc->State = AFP_DBG_MDL_INIT;
ACQUIRE_SPIN_LOCK(&AfpDebugSpinLock, &OldIrql); InsertTailList(&AfpDebugDelAllocHead, &pDelAlloc->Linkage); RELEASE_SPIN_LOCK(&AfpDebugSpinLock, OldIrql); } #endif
return(pDelAlloc); }
VOID FASTCALL AfpFreeDelAlloc( IN PDELAYEDALLOC pDelAlloc ) { KIRQL OldIrql;
#if DBG
ASSERT(pDelAlloc->Signature == AFP_DELALLOC_SIGNATURE);
pDelAlloc->State |= AFP_DBG_MDL_END;
ACQUIRE_SPIN_LOCK(&AfpDebugSpinLock, &OldIrql); RemoveEntryList(&pDelAlloc->Linkage);
pDelAlloc->Linkage.Flink = (PLIST_ENTRY)0x11111111; pDelAlloc->Linkage.Blink = (PLIST_ENTRY)0x33333333; RELEASE_SPIN_LOCK(&AfpDebugSpinLock, OldIrql); #endif
AfpFreeMemory(pDelAlloc); }
|