1286 lines
42 KiB
C
1286 lines
42 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
bulkw.c - this file needs to get folded into write.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the mini redirector call down routines pertaining to write
|
||
of file system objects.
|
||
|
||
Author:
|
||
|
||
Balan Sethu Raman [SethuR] 7-March-1995
|
||
|
||
Revision History:
|
||
|
||
Notes:
|
||
|
||
The WRITE_BULK is an example of a potential multi SMB exchange that uses the
|
||
associated exchange infra structure in the connection engine in conjunction with
|
||
the continuation capability in the ORDINARY_EXCHANGE.
|
||
|
||
The WRITE_BULK processing involves the following steps ...
|
||
|
||
1) send a SMB_WRITE_BULK request to the server.
|
||
|
||
2) process the SMB_WRITE_BULK response from the server and if successful
|
||
spin up SMB_WRITE_BULK_DATA requests to write the data to the server. There
|
||
are no responses from the server for the various SMB_WRITE_BULK_DATA requests.
|
||
|
||
3) On completion of the SMB_WRITE_BULK_DATA requests wait for the final
|
||
SMB_WRITE_BULK response from the server.
|
||
|
||
This sequence of SMB exchanges is implemented in the following manner ...
|
||
|
||
1) An instance of ORDINARY_EXCHANGE is created and submitted to the connection
|
||
engine spin up the initial request.
|
||
|
||
2) If the response indicated success the continuation routine in the ORDINARY_EXCHANGE
|
||
is set to MRxSmbWriteBulkContinuation.
|
||
|
||
3) On finalization by the connection engine the processing is resumed in
|
||
MRxSmbWriteBulkDataContinuation. Here the ORDINARY_EXCHANGE instance is reset,
|
||
the preparation made for receiving the final response. The SMB_WRITE_BULK_DATA
|
||
requests are spun up as associated exchanges. Currently the SMB_WRITE_BULK_DATA
|
||
requests are spun up in batches of atmost MAXIMUM_CONCURRENT_WRITE_BULK_DATA_REQUESTS
|
||
|
||
On completion ofone batch of requests the next batch is spun up. This is one place
|
||
where the logic needs to be fine tuned based upon observed performance. The
|
||
approaches can range from spinning one request at a time to the current implementation.
|
||
A variation would be to spin them up in batches but have each completion trigger of
|
||
further processing. This would involve changes in when the associated exchange
|
||
completion handler routine in the connection engine is activated.
|
||
|
||
One final note --- the ContinuationRoutine is changed on the fly by the bulk data
|
||
processing to ensure that the same ordinary exchange continuation infra structure
|
||
is used to deal with the end case.
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
#include "bulkw.h"
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_WRITE)
|
||
|
||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||
|
||
#define MIN_CHUNK_SIZE (0x1000)
|
||
|
||
#define MAXIMUM_CONCURRENT_WRITE_BULK_DATA_REQUESTS (5)
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, ProcessWriteBulkCompressed)
|
||
#pragma alloc_text(PAGE, MRxSmbBuildWriteBulk)
|
||
#pragma alloc_text(PAGE, MRxSmbFinishWriteBulkData)
|
||
#pragma alloc_text(PAGE, MRxSmbWriteBulkContinuation)
|
||
#pragma alloc_text(PAGE, MRxSmbBuildWriteBulkData)
|
||
#pragma alloc_text(PAGE, MRxSmbInitializeWriteBulkDataExchange)
|
||
#pragma alloc_text(PAGE, MRxSmbWriteBulkDataExchangeStart)
|
||
#pragma alloc_text(PAGE, MRxSmbWriteBulkDataExchangeFinalize)
|
||
#endif
|
||
|
||
extern SMB_EXCHANGE_DISPATCH_VECTOR SmbPseDispatch_Write;
|
||
|
||
|
||
//
|
||
// Forward declarations
|
||
//
|
||
|
||
NTSTATUS
|
||
MRxSmbBuildWriteBulkData (
|
||
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
|
||
IN PLARGE_INTEGER ByteOffsetAsLI,
|
||
IN UCHAR Sequence,
|
||
IN ULONG ByteCount,
|
||
IN ULONG Remaining
|
||
);
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbInitializeWriteBulkDataExchange(
|
||
PSMB_WRITE_BULK_DATA_EXCHANGE *pWriteBulkDataExchangePointer,
|
||
PSMB_PSE_ORDINARY_EXCHANGE pWriteExchange,
|
||
PSMB_HEADER pSmbHeader,
|
||
PREQ_WRITE_BULK_DATA pWriteBulkDataRequest,
|
||
PMDL pDataMdl,
|
||
ULONG DataSizeInBytes,
|
||
ULONG DataOffsetInBytes,
|
||
ULONG RemainingDataInBytes);
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbWriteBulkDataExchangeFinalize(
|
||
IN OUT struct _SMB_EXCHANGE *pExchange,
|
||
OUT BOOLEAN *pPostRequest);
|
||
|
||
VOID
|
||
ProcessWriteBulkCompressed (
|
||
IN PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine attempts to perform a write bulk operation.
|
||
|
||
Arguments:
|
||
|
||
OrdinaryExchange - pointer to the current ordinary exchange request.
|
||
|
||
Return Value:
|
||
|
||
NONE.
|
||
|
||
Notes:
|
||
|
||
rw->CompressedRequest - TRUE we have succeeded in making the buffer
|
||
compressed. FALSE otherwise.
|
||
|
||
This is the initial routine that is called to do the necessary preprocessing
|
||
of the only kind of compressed write requests that are handled on the client side
|
||
|
||
These are write requests that are page aligned for an integral number of pages
|
||
to a compressed server.
|
||
|
||
--*/
|
||
{
|
||
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
||
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
|
||
NTSTATUS status;
|
||
PVOID workSpaceBuffer;
|
||
ULONG workSpaceBufferSize;
|
||
ULONG workSpaceFragmentSize;
|
||
ULONG compressedInfoLength;
|
||
PCOMPRESSED_DATA_INFO compressedDataInfo;
|
||
ULONG i;
|
||
PMDL mdl;
|
||
ULONG headerLength;
|
||
|
||
//RNGFIX
|
||
//
|
||
// We can also use the call to RxGetCompressionWorkSpaceSize as a test to see
|
||
// if the current system knows how to handle the CompressionFormat/Engine on a
|
||
// read request.
|
||
//
|
||
// We also need a workspace buffer. We can get the size of this buffer from
|
||
// the call to RxGetCompressionWorkspace. We can have 1 statically allocated
|
||
// workspace buffer (per File! if we find we don't have one, then return
|
||
// a failure and do uncompressed writes!) This is recommended per file, since
|
||
// the size of the workspace is dependent on the compression type, which can
|
||
// vary on a per file basis.
|
||
//
|
||
// We must then pass the CDI ptr to the build write bulk request routine.
|
||
//
|
||
// We can then start writing the compressed data to the server in the finish
|
||
// routine.
|
||
//
|
||
//RNGFIX - remember to deallocate this buffer on the cleanup side!
|
||
|
||
PAGED_CODE();
|
||
|
||
rw->CompressedRequest = FALSE;
|
||
rw->DataOffset = 0;
|
||
rw->CompressedByteCount = 0;
|
||
|
||
//
|
||
// Calculate length of the needed CDI.
|
||
//
|
||
|
||
compressedInfoLength = (sizeof(COMPRESSED_DATA_INFO) + 7 +
|
||
(((rw->ThisByteCount + MIN_CHUNK_SIZE - 1) / MIN_CHUNK_SIZE) * 4))
|
||
&~7;
|
||
ASSERT( compressedInfoLength <= 65535 );
|
||
|
||
//
|
||
// Allocate the buffer to compress into. We could get tricky here and
|
||
// allocate a portion of the buffer, like 15/16ths if the compression unit
|
||
// shift (this would be for 16 sectors per compression unit). We will
|
||
// allocate the CDI along with this.
|
||
//
|
||
|
||
compressedDataInfo = (PCOMPRESSED_DATA_INFO)RxAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
rw->ThisByteCount + compressedInfoLength,
|
||
MRXSMB_RW_POOLTAG);
|
||
|
||
//
|
||
// If we fail, just return an error.
|
||
//
|
||
if ( compressedDataInfo == NULL ) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Save buffer address (not we skip past the CDI). We need to back
|
||
// up the buffer address on the free later.
|
||
//
|
||
|
||
rw->BulkBuffer = (PCHAR)compressedDataInfo + compressedInfoLength;
|
||
rw->DataOffset = (USHORT)compressedInfoLength;
|
||
|
||
//
|
||
// Fill in the CDI. RNGFIX - we need to get this data from the open!
|
||
// CODE.IMPROVEMENT
|
||
//
|
||
|
||
compressedDataInfo->CompressionFormatAndEngine = COMPRESSION_FORMAT_LZNT1;
|
||
compressedDataInfo->ChunkShift = 0xC;
|
||
compressedDataInfo->CompressionUnitShift = 0xD;
|
||
compressedDataInfo->ClusterShift = 0x9;
|
||
|
||
//
|
||
// Allocate the workspace buffer. We will allocate this separately, since
|
||
// it is only needed for the duration of the compression operation. We'll
|
||
// free it when we're done. We could just do this once when the file is
|
||
// is opened. We know all of the info at that time, including the fact that
|
||
// it is compressed. However, we'd be holding onto pool for much longer.
|
||
//
|
||
|
||
//RNGFIX - COMRPRESSION_FORMAT_LZNT1 should be from OpenFile!
|
||
//CODE.IMPROVEMENT
|
||
status = RtlGetCompressionWorkSpaceSize(
|
||
COMPRESSION_FORMAT_LZNT1,
|
||
&workSpaceBufferSize,
|
||
&workSpaceFragmentSize );
|
||
|
||
workSpaceBuffer = RxAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
workSpaceBufferSize,
|
||
MRXSMB_RW_POOLTAG);
|
||
|
||
if ( workSpaceBuffer == NULL ) {
|
||
RxFreePool( compressedDataInfo );
|
||
rw->BulkBuffer = NULL;
|
||
return;
|
||
}
|
||
|
||
status = RtlCompressChunks(
|
||
rw->UserBufferBase + rw->ThisBufferOffset,
|
||
rw->ThisByteCount,
|
||
rw->BulkBuffer,
|
||
rw->ThisByteCount,
|
||
compressedDataInfo,
|
||
compressedInfoLength,
|
||
workSpaceBuffer );
|
||
|
||
RxFreePool( workSpaceBuffer );
|
||
|
||
if ( status != RX_MAP_STATUS(SUCCESS) ) {
|
||
RxFreePool( compressedDataInfo );
|
||
return;
|
||
}
|
||
|
||
rw->CompressedRequest = TRUE;
|
||
|
||
//
|
||
// Calculate length of compressed data.
|
||
//
|
||
|
||
ASSERT( compressedDataInfo->NumberOfChunks < 256 );
|
||
|
||
rw->CompressedByteCount = 0;
|
||
for ( i = 0; i < compressedDataInfo->NumberOfChunks; i++ ) {
|
||
rw->CompressedByteCount += compressedDataInfo->CompressedChunkSizes[i];
|
||
}
|
||
|
||
//
|
||
// Build an mdl from the receive buffer - just after the SMB header
|
||
//
|
||
|
||
// Use the larger of the two headers we'll have to send.
|
||
|
||
headerLength = MAX( FIELD_OFFSET(REQ_WRITE_BULK_DATA, Buffer),
|
||
FIELD_OFFSET(REQ_WRITE_BULK, Buffer) );
|
||
|
||
mdl = (PMDL)(((ULONG)StufferState->BufferBase + sizeof(SMB_HEADER)
|
||
+ 10 + headerLength) & ~7);
|
||
|
||
//
|
||
// We will use the same mdl for both sending the CDI and the actual
|
||
// compressed data. This mdl is part of the receive buffer - just after
|
||
// the header.
|
||
//
|
||
|
||
// ASSERT( rw->CompressedByteCount >= compressedInfoLength );
|
||
MmInitializeMdl( mdl, (PCHAR)rw->BulkBuffer - compressedInfoLength, compressedInfoLength );
|
||
|
||
MmBuildMdlForNonPagedPool( mdl );
|
||
|
||
return;
|
||
|
||
} // ProcessWriteBulkCompressed
|
||
|
||
NTSTATUS
|
||
MRxSmbBuildWriteBulk (
|
||
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
|
||
IN PLARGE_INTEGER ByteOffsetAsLI,
|
||
IN ULONG ByteCount,
|
||
IN ULONG MaxMessageSize,
|
||
IN PVOID CompressedDataInfo,
|
||
IN ULONG CompressedInfoSize,
|
||
IN ULONG CompressedBufferSize,
|
||
IN PMDL CompressedInfoMdl
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This builds a WriteBulk SMB. We don't have to worry about login id and such
|
||
since that is done by the connection engine....pretty neat huh? All we have
|
||
to do is format up the bits.
|
||
|
||
|
||
Arguments:
|
||
|
||
StufferState - the state of the smbbuffer from the stuffer's point of view
|
||
|
||
ByteOffsetAsLI - the byte offset in the file where we want to write
|
||
|
||
ByteCount - the length of the data to be written
|
||
|
||
MaxMessageSize - the maximum message size that we can send
|
||
|
||
CompressedDataInfo - pointer to the COMPRESSED_DATA_INFO structure
|
||
|
||
CompressedInfoSize - size of the COMPRESSED_DATA_INFO structure (or zero)
|
||
|
||
CompressedBufferSize - size of the Compressed Data
|
||
|
||
CompressedInfoMdl - pointer to the compressed data info mdl
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS
|
||
SUCCESS
|
||
NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
|
||
|
||
Notes:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PRX_CONTEXT RxContext = StufferState->RxContext;
|
||
RxCaptureFcb;RxCaptureFobx;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
PNT_SMB_HEADER SmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
|
||
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
ULONG OffsetLow,OffsetHigh;
|
||
UCHAR WriteMode = 0;
|
||
UCHAR CompressionTechnology;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbBuildWriteBulk\n", 0 ));
|
||
|
||
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
||
|
||
OffsetLow = ByteOffsetAsLI->LowPart;
|
||
OffsetHigh = ByteOffsetAsLI->HighPart;
|
||
|
||
COVERED_CALL(MRxSmbStartSMBCommand( StufferState, SetInitialSMB_Never,
|
||
SMB_COM_WRITE_BULK, SMB_REQUEST_SIZE(WRITE_BULK),
|
||
NO_EXTRA_DATA,
|
||
NO_SPECIAL_ALIGNMENT,
|
||
RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
|
||
0,0,0,0 STUFFERTRACE(Dbg,'FC'))
|
||
);
|
||
|
||
RxDbgTrace(0, Dbg,("First write bulk status = %lu\n",Status));
|
||
// MRxSmbDumpStufferState (1000,"SMB w/WRITE BULK before stuffing",StufferState);
|
||
|
||
if (FlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,LOWIO_READWRITEFLAG_PAGING_IO)) {
|
||
SmbPutAlignedUshort(
|
||
&SmbHeader->Flags2,
|
||
SmbGetAlignedUshort(&SmbHeader->Flags2)|SMB_FLAGS2_PAGING_IO);
|
||
}
|
||
|
||
ASSERT( SMB_WMODE_WRITE_THROUGH == 1 );
|
||
if ( FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WRITE_THROUGH) ) {
|
||
WriteMode |= SMB_WMODE_WRITE_THROUGH;
|
||
}
|
||
|
||
if ( CompressedInfoSize ) {
|
||
CompressionTechnology = CompressionTechnologyOne;
|
||
} else {
|
||
CompressionTechnology = CompressionTechnologyNone;
|
||
}
|
||
|
||
MRxSmbStuffSMB (StufferState,
|
||
"0yywDddddB!",
|
||
// 0 UCHAR WordCount; // Count of parameter words = 12
|
||
WriteMode, // y UCHAR Flags; // Flags byte
|
||
CompressionTechnology, // y UCHAR CompressionTechnology
|
||
// CompressionTechnology
|
||
smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
|
||
SMB_OFFSET_CHECK(WRITE_BULK, Offset)
|
||
OffsetLow, OffsetHigh, // Dd LARGE_INTEGER Offset; // Offset in file to begin write
|
||
ByteCount, // d _ULONG( TotalCount ); // Total amount of data in this request (ie bytes covered)
|
||
CompressedBufferSize, // d _ULONG( DataCount ); // Count of data bytes in this message, replaces ByteCount
|
||
MaxMessageSize, // d _ULONG( MessageSize );
|
||
// Maximum bytes we can send per message
|
||
// B _USHORT( ByteCount ); // Count of data bytes = 0, not used
|
||
SMB_WCT_CHECK(12) CompressedInfoSize
|
||
// UCHAR Buffer[1];
|
||
);
|
||
|
||
SmbPutUshort( StufferState->CurrentBcc, (USHORT)CompressedInfoSize );
|
||
|
||
if ( CompressedInfoSize ) {
|
||
MRxSmbStuffAppendRawData( StufferState, CompressedInfoMdl );
|
||
}
|
||
|
||
//MRxSmbDumpStufferState (700,"SMB w/WRITE BULK after stuffing",StufferState);
|
||
|
||
FINALLY:
|
||
RxDbgTraceUnIndent(-1, Dbg);
|
||
return Status;
|
||
|
||
} // MRxSmbBuildWriteBulk
|
||
|
||
NTSTATUS
|
||
MRxSmbFinishWriteBulkData (
|
||
IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine completes the write bulk request processing. This routine must always
|
||
return STATUS_PENDING to follow the correct processing in the ordinary exchange
|
||
logic for synchronous operations. This is because this continuation routine will
|
||
be invoked in other thread contexts
|
||
|
||
This routine is used to wrap up synchronous bulk operations
|
||
|
||
Arguments:
|
||
|
||
OrdinaryExchange - the exchange instance
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT(!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
|
||
RxDbgTrace(0,Dbg,("Invoking Bulk Write wrap up for ....%lx\n",OrdinaryExchange));
|
||
|
||
RxSignalSynchronousWaiter(RxContext);
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbWriteBulkContinuation(
|
||
IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine continues the Write bulk data request processing on receipt of
|
||
a valid SMB_WRITE_BULK response from the server.
|
||
|
||
Arguments:
|
||
|
||
OrdinaryExchange - the exchange instance
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
|
||
PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
|
||
PSMB_PSE_OE_READWRITE rw = &OrdinaryExchange->ReadWrite;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
PSMB_EXCHANGE pExchange = &OrdinaryExchange->Exchange;
|
||
PMDL HeaderMdl = StufferState->HeaderMdl;
|
||
PMDL SubmitMdl = StufferState->HeaderPartialMdl;
|
||
ULONG MessageSize;
|
||
ULONG SendBufferLength;
|
||
ULONG RemainingByteCount,ThisBufferOffset;
|
||
ULONG PartialBytes;
|
||
LARGE_INTEGER ByteOffsetAsLI;
|
||
PMDL DataMdl;
|
||
PMDL SourceMdl;
|
||
PREQ_WRITE_BULK_DATA WriteBulkHeader;
|
||
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
||
PSMB_HEADER pWriteBulkDataRequestSmbHeader;
|
||
ULONG headerLength;
|
||
ULONG ActiveWriteBulkDataRequests = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
headerLength = MAX( FIELD_OFFSET(REQ_WRITE_BULK_DATA, Buffer),
|
||
FIELD_OFFSET(REQ_WRITE_BULK, Buffer) );
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbWriteBulkContinuation\n"));
|
||
ASSERT( NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT );
|
||
|
||
RxDbgTrace(0, Dbg, ("-->BytesReturned=%08lx\n", rw->BytesReturned));
|
||
|
||
ASSERT( !RxShouldPostCompletion());
|
||
|
||
//
|
||
// Pick up our maximum message size
|
||
//
|
||
|
||
pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
||
|
||
MessageSize = MIN( rw->MaximumSendSize,
|
||
pServerEntry->pTransport->MaximumSendSize);
|
||
ASSERT( MessageSize != 0 );
|
||
ASSERT( rw->ThisByteCount != 0);
|
||
|
||
ByteOffsetAsLI.QuadPart = rw->ByteOffsetAsLI.QuadPart;
|
||
|
||
if (!FlagOn(rw->Flags,OE_RW_FLAG_WRITE_BULK_DATA_INITIALIZATION_DONE)) {
|
||
SetFlag(rw->Flags,OE_RW_FLAG_WRITE_BULK_DATA_INITIALIZATION_DONE);
|
||
|
||
SmbCeResetExchange((PSMB_EXCHANGE)OrdinaryExchange);
|
||
|
||
ClearFlag(
|
||
OrdinaryExchange->Flags,
|
||
(SMBPSE_OE_FLAG_HEADER_ALREADY_PARSED |
|
||
SMBPSE_OE_FLAG_OE_ALREADY_RESUMED) );
|
||
|
||
SmbCeIncrementPendingLocalOperations((PSMB_EXCHANGE)OrdinaryExchange);
|
||
|
||
if (OrdinaryExchange->Status == STATUS_SUCCESS) {
|
||
SmbCeReceive((PSMB_EXCHANGE)OrdinaryExchange);
|
||
|
||
//
|
||
// Okay... we're now going to transform the exchange packet into one
|
||
// that we can use for the WRITE_BULK_DATA request.
|
||
//
|
||
|
||
MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
|
||
|
||
//
|
||
// Build a generic WriteBulkData request. We'll fill in the specifics
|
||
// as we re-use this buffer.
|
||
//
|
||
|
||
pWriteBulkDataRequestSmbHeader = (PSMB_HEADER)StufferState->BufferBase;
|
||
WriteBulkHeader = (PREQ_WRITE_BULK_DATA)((PCHAR)StufferState->BufferBase +
|
||
sizeof(SMB_HEADER));
|
||
|
||
MRxSmbBuildWriteBulkData(
|
||
StufferState,
|
||
&ByteOffsetAsLI,
|
||
rw->Sequence,
|
||
0,
|
||
0);
|
||
|
||
//
|
||
// If we have compressed data, pick up the corresponding byte count and
|
||
// Mdl for the data. If we partial, we'll need to pick up another Mdl too.
|
||
//
|
||
|
||
ASSERT( CompressionTechnologyNone == 0 );
|
||
if ( rw->CompressedRequest &&
|
||
rw->CompressionTechnology ) {
|
||
// Eventhough we have sent compressed the entire buffer and sent the
|
||
// compression meta data to the server it might choose to accept
|
||
// less data. In such cases the client should be prepared to scale back
|
||
// the data that needs to be sent. The server side will ensure that
|
||
// the data that is accepted will correspond to an integral number of
|
||
// chunks. This will ensure that the subsequent requests have a chance
|
||
// of being compressed. If this is not true we have no way of restarting.
|
||
// Based upon the compressed length that has been accepted we need to
|
||
// determine the number of chunks. This can be translated to the
|
||
// equivalent number of uncompressed bytes which will establish the
|
||
// resumption point.
|
||
//
|
||
// Use the space in the receive buffer - after the header mdl - for
|
||
// the data mdl.
|
||
//
|
||
|
||
if (rw->ThisByteCount < rw->CompressedByteCount) {
|
||
// This is the case where the server was not able to accept all
|
||
// of our compressed data in one shot.
|
||
|
||
ULONG NumberOfChunks = 0;
|
||
ULONG CumulativeChunkSize = 0;
|
||
PCOMPRESSED_DATA_INFO pCompressedDataInfo;
|
||
|
||
pCompressedDataInfo = (PCOMPRESSED_DATA_INFO)
|
||
((PCHAR)rw->BulkBuffer - rw->DataOffset);
|
||
|
||
for (;;) {
|
||
ULONG TempSize;
|
||
|
||
TempSize = CumulativeChunkSize +
|
||
pCompressedDataInfo->CompressedChunkSizes[NumberOfChunks];
|
||
|
||
if (TempSize <= rw->ThisByteCount) {
|
||
NumberOfChunks++;
|
||
CumulativeChunkSize = TempSize;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT(CumulativeChunkSize == rw->ThisByteCount);
|
||
pCompressedDataInfo->NumberOfChunks = (USHORT)NumberOfChunks;
|
||
|
||
rw->CompressedByteCount = CumulativeChunkSize;
|
||
}
|
||
|
||
RemainingByteCount = rw->CompressedByteCount;
|
||
|
||
SourceMdl = (PMDL)(((ULONG)StufferState->BufferBase +
|
||
sizeof(SMB_HEADER) + 10 + headerLength) & ~7);
|
||
|
||
//
|
||
// Build an mdl for describing the compressed data.
|
||
//
|
||
|
||
MmInitializeMdl( SourceMdl, rw->BulkBuffer, rw->CompressedByteCount );
|
||
MmBuildMdlForNonPagedPool( SourceMdl );
|
||
|
||
ThisBufferOffset = 0;
|
||
} else {
|
||
|
||
// Pick up the rest of the data, and no need to partial.
|
||
|
||
RemainingByteCount = rw->ThisByteCount;
|
||
SourceMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
|
||
ThisBufferOffset = rw->ThisBufferOffset;
|
||
}
|
||
|
||
rw->PartialBytes = 0;
|
||
rw->BytesReturned = 0;
|
||
|
||
if (!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
|
||
KeInitializeEvent(
|
||
&RxContext->SyncEvent,
|
||
NotificationEvent,
|
||
FALSE );
|
||
}
|
||
} else {
|
||
Status = OrdinaryExchange->Status;
|
||
RemainingByteCount = 0;
|
||
}
|
||
} else {
|
||
pWriteBulkDataRequestSmbHeader = (PSMB_HEADER)StufferState->BufferBase;
|
||
WriteBulkHeader = (PREQ_WRITE_BULK_DATA)((PCHAR)StufferState->BufferBase +
|
||
sizeof(SMB_HEADER));
|
||
|
||
ByteOffsetAsLI.QuadPart += rw->PartialBytes;
|
||
ThisBufferOffset = rw->PartialBytes;
|
||
|
||
if ( rw->CompressedRequest &&
|
||
rw->CompressionTechnology ) {
|
||
RemainingByteCount = rw->CompressedByteCount - rw->PartialBytes;
|
||
|
||
SourceMdl = (PMDL)(((ULONG)StufferState->BufferBase +
|
||
sizeof(SMB_HEADER) + 10 + headerLength) & ~7);
|
||
} else {
|
||
RemainingByteCount = rw->ThisByteCount - rw->PartialBytes;
|
||
|
||
SourceMdl = LowIoContext->ParamsFor.ReadWrite.Buffer;
|
||
}
|
||
|
||
if ((OrdinaryExchange->Status != STATUS_SUCCESS) &&
|
||
(OrdinaryExchange->Status != STATUS_MORE_PROCESSING_REQUIRED)) {
|
||
RemainingByteCount = 0;
|
||
Status = OrdinaryExchange->Status;
|
||
}
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("ABWR: OE %lx TBC %lx RBC %lx TBO %lx\n",
|
||
OrdinaryExchange,
|
||
rw->ThisByteCount,
|
||
rw->RemainingByteCount,
|
||
ThisBufferOffset));
|
||
}
|
||
|
||
while (RemainingByteCount > 0) {
|
||
BOOLEAN AssociatedExchangeCompletionHandlerActivated = FALSE;
|
||
PSMB_WRITE_BULK_DATA_EXCHANGE pWriteBulkDataExchange;
|
||
|
||
//
|
||
// Check if we need to build a partial mdl...
|
||
//
|
||
|
||
SendBufferLength = MIN( MessageSize, RemainingByteCount );
|
||
|
||
// Get our offset and length in prepartion to build and
|
||
// send the message.
|
||
//
|
||
// We manually setup the fields that change in the WriteBulkData
|
||
// message, rather than build a new header each time to save
|
||
// time and effort. This will happen once per message that we
|
||
// send.
|
||
//
|
||
|
||
RemainingByteCount -= SendBufferLength;
|
||
|
||
SmbPutUlong( &WriteBulkHeader->Offset.LowPart, ByteOffsetAsLI.LowPart );
|
||
SmbPutUlong( &WriteBulkHeader->Offset.HighPart, ByteOffsetAsLI.HighPart );
|
||
SmbPutUlong( &WriteBulkHeader->DataCount, SendBufferLength );
|
||
SmbPutUlong( &WriteBulkHeader->Remaining, RemainingByteCount );
|
||
|
||
Status = MRxSmbInitializeWriteBulkDataExchange(
|
||
&pWriteBulkDataExchange,
|
||
OrdinaryExchange,
|
||
pWriteBulkDataRequestSmbHeader,
|
||
WriteBulkHeader,
|
||
SourceMdl,
|
||
SendBufferLength,
|
||
ThisBufferOffset,
|
||
RemainingByteCount);
|
||
|
||
// Advance offset and reduce the number of bytes written.
|
||
|
||
ByteOffsetAsLI.QuadPart += SendBufferLength;
|
||
ThisBufferOffset += SendBufferLength;
|
||
rw->PartialBytes += SendBufferLength;
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
ActiveWriteBulkDataRequests++;
|
||
AssociatedExchangeCompletionHandlerActivated =
|
||
((ActiveWriteBulkDataRequests == MAXIMUM_CONCURRENT_WRITE_BULK_DATA_REQUESTS) ||
|
||
(RemainingByteCount == 0));
|
||
|
||
if (AssociatedExchangeCompletionHandlerActivated &&
|
||
(RemainingByteCount == 0)) {
|
||
|
||
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationCompleted;
|
||
|
||
if (!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
|
||
OrdinaryExchange->ContinuationRoutine = MRxSmbFinishWriteBulkData;
|
||
}
|
||
}
|
||
|
||
Status = SmbCeInitiateAssociatedExchange(
|
||
(PSMB_EXCHANGE)pWriteBulkDataExchange,
|
||
AssociatedExchangeCompletionHandlerActivated);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
RxDbgTrace( 0, Dbg, ("SmbPseExchangeReceive_default: SmbCeSend returned %lx\n",Status));
|
||
goto FINALLY;
|
||
}
|
||
|
||
if (AssociatedExchangeCompletionHandlerActivated) {
|
||
if (!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
|
||
RxWaitSync( RxContext );
|
||
Status = STATUS_SUCCESS;
|
||
|
||
if (RemainingByteCount == 0) {
|
||
break;
|
||
} else {
|
||
// Reinitialize the event
|
||
KeInitializeEvent(
|
||
&RxContext->SyncEvent,
|
||
NotificationEvent,
|
||
FALSE );
|
||
ActiveWriteBulkDataRequests = 0;
|
||
}
|
||
} else {
|
||
// Map the status to delay cleanup operations.
|
||
Status = STATUS_PENDING;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
FINALLY:
|
||
|
||
if (Status != STATUS_PENDING) {
|
||
OrdinaryExchange->OpSpecificState = SmbPseOEInnerIoStates_OperationCompleted;
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
if(rw->CompressedRequest &&
|
||
rw->CompressionTechnology) {
|
||
PCOMPRESSED_DATA_INFO pCompressedDataInfo;
|
||
|
||
pCompressedDataInfo = (PCOMPRESSED_DATA_INFO)
|
||
((PCHAR)rw->BulkBuffer - rw->DataOffset);
|
||
|
||
rw->BytesReturned = pCompressedDataInfo->NumberOfChunks * MIN_CHUNK_SIZE;
|
||
} else {
|
||
rw->BytesReturned = rw->ThisByteCount;
|
||
}
|
||
} else {
|
||
rw->BytesReturned = 0;
|
||
}
|
||
|
||
if (rw->CompressedRequest &&
|
||
rw->BulkBuffer != NULL) {
|
||
// Free buffer from start of CDI
|
||
RxFreePool( (PCHAR)rw->BulkBuffer - rw->DataOffset );
|
||
rw->BulkBuffer = NULL;
|
||
}
|
||
|
||
if ( rw->CompressedRequest &&
|
||
rw->CompressionTechnology ) {
|
||
SourceMdl = (PMDL)(((ULONG)StufferState->BufferBase +
|
||
sizeof(SMB_HEADER) + 10 + headerLength) & ~7);
|
||
|
||
MmPrepareMdlForReuse(SourceMdl);
|
||
}
|
||
|
||
if (!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
|
||
KeInitializeEvent(
|
||
&RxContext->SyncEvent,
|
||
NotificationEvent,
|
||
FALSE );
|
||
}
|
||
|
||
OrdinaryExchange->ContinuationRoutine = NULL;
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("OE %lx TBC %lx RBC %lx BR %lx TBO %lx\n",
|
||
OrdinaryExchange,rw->ThisByteCount,
|
||
rw->RemainingByteCount,
|
||
rw->BytesReturned,
|
||
rw->ThisBufferOffset));
|
||
|
||
|
||
SmbCeDecrementPendingLocalOperationsAndFinalize((PSMB_EXCHANGE)OrdinaryExchange);
|
||
|
||
if (!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
|
||
RxWaitSync( RxContext );
|
||
} else {
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("ABWC: OE: %lx Status %lx\n",
|
||
OrdinaryExchange,
|
||
Status));
|
||
}
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbWriteBulkContinuation returning %08lx\n", Status ));
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbBuildWriteBulkData (
|
||
IN OUT PSMBSTUFFER_BUFFER_STATE StufferState,
|
||
IN PLARGE_INTEGER ByteOffsetAsLI,
|
||
IN UCHAR Sequence,
|
||
IN ULONG ByteCount,
|
||
IN ULONG Remaining
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This builds a WriteBulk SMB. We don't have to worry about login id and such
|
||
since that is done by the connection engine....pretty neat huh? All we have
|
||
to do is format up the bits.
|
||
|
||
|
||
Arguments:
|
||
|
||
StufferState - the state of the smbbuffer from the stuffer's point of view
|
||
ByteOffsetAsLI - the byte offset in the file where we want to read
|
||
Sequence - this WriteBulkData exchange sequence
|
||
ByteCount - the length of the data to be written
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
STATUS_SUCCESS
|
||
STATUS_NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
|
||
|
||
Notes:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PRX_CONTEXT RxContext = StufferState->RxContext;
|
||
RxCaptureFcb;RxCaptureFobx;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
PNT_SMB_HEADER SmbHeader = (PNT_SMB_HEADER)(StufferState->BufferBase);
|
||
|
||
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
||
ULONG OffsetLow,OffsetHigh;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbBuildWriteBulk\n", 0 ));
|
||
|
||
ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
|
||
|
||
OffsetLow = ByteOffsetAsLI->LowPart;
|
||
OffsetHigh = ByteOffsetAsLI->HighPart;
|
||
|
||
StufferState->CurrentPosition = (PCHAR)(SmbHeader + 1);
|
||
SmbHeader->Command = SMB_COM_WRITE_BULK_DATA;
|
||
|
||
COVERED_CALL(MRxSmbStartSMBCommand( StufferState, SetInitialSMB_Never,
|
||
SMB_COM_WRITE_BULK_DATA,
|
||
SMB_REQUEST_SIZE(WRITE_BULK),
|
||
NO_EXTRA_DATA,
|
||
NO_SPECIAL_ALIGNMENT,
|
||
RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
|
||
0,0,0,0 STUFFERTRACE(Dbg,'FC'));
|
||
);
|
||
|
||
RxDbgTrace(0, Dbg,("First write bulk data status = %lu\n",Status));
|
||
MRxSmbDumpStufferState (1000,"SMB w/WRITE BULK DATA before stuffing",StufferState);
|
||
|
||
if ( FlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,LOWIO_READWRITEFLAG_PAGING_IO)) {
|
||
SmbPutAlignedUshort(
|
||
&SmbHeader->Flags2,
|
||
SmbGetAlignedUshort(&SmbHeader->Flags2)|SMB_FLAGS2_PAGING_IO);
|
||
}
|
||
|
||
MRxSmbStuffSMB (StufferState,
|
||
"0yywdDddB!",
|
||
// 0 UCHAR WordCount; // Count of parameter words = 10
|
||
Sequence, // y UCHAR Sequence; // Exchange sequence handle
|
||
0, // y UCHAR Reserved;
|
||
smbSrvOpen->Fid, // w _USHORT( Fid ); // File handle
|
||
ByteCount, // d _ULONG( DataCount ); // Count of bytes, replaces ByteCount
|
||
SMB_OFFSET_CHECK(WRITE_BULK_DATA, Offset)
|
||
OffsetLow, OffsetHigh, // Dd LARGE_INTEGER Offset; // Offset in file to begin write
|
||
Remaining, // d _ULONG( Remaining ); // Bytes remaining to be written
|
||
// B _USHORT( ByteCount ); // Count of data bytes = 0, not used
|
||
SMB_WCT_CHECK(10) 0
|
||
// UCHAR Buffer[1];
|
||
);
|
||
|
||
MRxSmbDumpStufferState (700,"SMB w/WRITE BULK DATA after stuffing",StufferState);
|
||
|
||
FINALLY:
|
||
RxDbgTraceUnIndent(-1, Dbg);
|
||
return(Status);
|
||
|
||
} // MRxSmbBuildWriteBulkData
|
||
|
||
extern SMB_EXCHANGE_DISPATCH_VECTOR WriteBulkDataExchangeDispatchVector;
|
||
|
||
NTSTATUS
|
||
MRxSmbInitializeWriteBulkDataExchange(
|
||
PSMB_WRITE_BULK_DATA_EXCHANGE *pWriteBulkDataExchangePointer,
|
||
PSMB_PSE_ORDINARY_EXCHANGE pWriteExchange,
|
||
PSMB_HEADER pSmbHeader,
|
||
PREQ_WRITE_BULK_DATA pWriteBulkDataRequest,
|
||
PMDL pDataMdl,
|
||
ULONG DataSizeInBytes,
|
||
ULONG DataOffsetInBytes,
|
||
ULONG RemainingDataInBytes)
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
ULONG HeaderMdlSize;
|
||
ULONG DataMdlSize;
|
||
ULONG WriteBulkDataExchangeSize;
|
||
|
||
PSMB_WRITE_BULK_DATA_EXCHANGE pWriteBulkDataExchange;
|
||
|
||
PAGED_CODE();
|
||
|
||
HeaderMdlSize = MmSizeOfMdl(
|
||
0,
|
||
sizeof(SMB_HEADER) + TRANSPORT_HEADER_SIZE + FIELD_OFFSET(REQ_WRITE_BULK_DATA,Buffer));
|
||
|
||
DataMdlSize = MmSizeOfMdl(
|
||
0,
|
||
DataSizeInBytes);
|
||
|
||
|
||
WriteBulkDataExchangeSize = FIELD_OFFSET(SMB_WRITE_BULK_DATA_EXCHANGE,Buffer) +
|
||
HeaderMdlSize +
|
||
DataMdlSize +
|
||
TRANSPORT_HEADER_SIZE +
|
||
sizeof(SMB_HEADER) +
|
||
FIELD_OFFSET(REQ_WRITE_BULK_DATA,Buffer);
|
||
|
||
pWriteBulkDataExchange = (PSMB_WRITE_BULK_DATA_EXCHANGE)
|
||
SmbMmAllocateVariableLengthExchange(
|
||
WRITE_BULK_DATA_EXCHANGE,
|
||
WriteBulkDataExchangeSize);
|
||
|
||
if (pWriteBulkDataExchange != NULL) {
|
||
pWriteBulkDataExchange->pHeaderMdl =
|
||
(PMDL)((PBYTE)pWriteBulkDataExchange +
|
||
FIELD_OFFSET(SMB_WRITE_BULK_DATA_EXCHANGE,Buffer));
|
||
|
||
pWriteBulkDataExchange->pDataMdl =
|
||
(PMDL)((PBYTE)pWriteBulkDataExchange->pHeaderMdl + HeaderMdlSize);
|
||
|
||
pWriteBulkDataExchange->pHeader =
|
||
(PSMB_HEADER)((PBYTE)pWriteBulkDataExchange->pDataMdl +
|
||
DataMdlSize + TRANSPORT_HEADER_SIZE);
|
||
|
||
pWriteBulkDataExchange->pWriteBulkDataRequest =
|
||
(PREQ_WRITE_BULK_DATA)(pWriteBulkDataExchange->pHeader + 1);
|
||
|
||
pWriteBulkDataExchange->WriteBulkDataRequestLength =
|
||
sizeof(SMB_HEADER) +
|
||
FIELD_OFFSET(REQ_WRITE_BULK_DATA,Buffer) +
|
||
DataSizeInBytes;
|
||
|
||
RtlCopyMemory(
|
||
pWriteBulkDataExchange->pHeader,
|
||
pSmbHeader,
|
||
sizeof(SMB_HEADER));
|
||
|
||
RtlCopyMemory(
|
||
pWriteBulkDataExchange->pWriteBulkDataRequest,
|
||
pWriteBulkDataRequest,
|
||
FIELD_OFFSET(REQ_WRITE_BULK_DATA,Buffer));
|
||
|
||
RxInitializeHeaderMdl(
|
||
pWriteBulkDataExchange->pHeaderMdl,
|
||
pWriteBulkDataExchange->pHeader,
|
||
sizeof(SMB_HEADER) + FIELD_OFFSET(REQ_WRITE_BULK_DATA,Buffer));
|
||
|
||
RxBuildHeaderMdlForNonPagedPool(pWriteBulkDataExchange->pHeaderMdl);
|
||
|
||
IoBuildPartialMdl(
|
||
pDataMdl,
|
||
pWriteBulkDataExchange->pDataMdl,
|
||
(PBYTE)MmGetMdlVirtualAddress(pDataMdl) + DataOffsetInBytes,
|
||
DataSizeInBytes);
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("Bulk Data O: %lx, Partial %lx Offset %lx Size %lx\n",
|
||
pDataMdl->MappedSystemVa,
|
||
pWriteBulkDataExchange->pDataMdl->MappedSystemVa,
|
||
DataOffsetInBytes,
|
||
DataSizeInBytes));
|
||
|
||
pWriteBulkDataExchange->pHeaderMdl->Next = pWriteBulkDataExchange->pDataMdl;
|
||
pWriteBulkDataExchange->pDataMdl->Next = NULL;
|
||
|
||
// Initialize the associated exchange.
|
||
Status = SmbCeInitializeAssociatedExchange(
|
||
(PSMB_EXCHANGE *)&pWriteBulkDataExchange,
|
||
(PSMB_EXCHANGE)pWriteExchange,
|
||
WRITE_BULK_DATA_EXCHANGE,
|
||
&WriteBulkDataExchangeDispatchVector);
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
pWriteBulkDataExchange->Mid = pWriteExchange->Mid;
|
||
SetFlag(
|
||
pWriteBulkDataExchange->SmbCeFlags,
|
||
(SMBCE_EXCHANGE_MID_VALID | SMBCE_EXCHANGE_RETAIN_MID));
|
||
|
||
*pWriteBulkDataExchangePointer = pWriteBulkDataExchange;
|
||
} else {
|
||
BOOLEAN PostRequest = FALSE;
|
||
|
||
MRxSmbWriteBulkDataExchangeFinalize(
|
||
(PSMB_EXCHANGE)pWriteBulkDataExchange,
|
||
&PostRequest);
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbWriteBulkDataExchangeStart(
|
||
IN struct _SMB_EXCHANGE *pExchange)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initiates the wriet bulk data exchange operation
|
||
|
||
Arguments:
|
||
|
||
pExchange - pointer to the bulk write data exchange instance.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PSMB_WRITE_BULK_DATA_EXCHANGE pWriteBulkDataExchange;
|
||
|
||
PAGED_CODE();
|
||
|
||
pWriteBulkDataExchange = (PSMB_WRITE_BULK_DATA_EXCHANGE)pExchange;
|
||
|
||
IF_DEBUG {
|
||
ULONG Length = 0;
|
||
PMDL pTempMdl;
|
||
|
||
pTempMdl = pWriteBulkDataExchange->pHeaderMdl;
|
||
|
||
while (pTempMdl != NULL) {
|
||
Length += pTempMdl->ByteCount;
|
||
pTempMdl = pTempMdl->Next;
|
||
}
|
||
|
||
ASSERT(Length == pWriteBulkDataExchange->WriteBulkDataRequestLength);
|
||
}
|
||
|
||
Status = SmbCeSend(
|
||
pExchange,
|
||
0,
|
||
pWriteBulkDataExchange->pHeaderMdl,
|
||
pWriteBulkDataExchange->WriteBulkDataRequestLength);
|
||
|
||
if ((Status != STATUS_PENDING) &&
|
||
(Status != STATUS_SUCCESS)) {
|
||
|
||
BOOLEAN PostRequest = FALSE;
|
||
|
||
MRxSmbWriteBulkDataExchangeFinalize(
|
||
(PSMB_EXCHANGE)pWriteBulkDataExchange,
|
||
&PostRequest);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbWriteBulkDataExchangeSendCompletionHandler(
|
||
IN struct _SMB_EXCHANGE *pExchange, // The exchange instance
|
||
IN PMDL pDataBuffer,
|
||
IN NTSTATUS SendCompletionStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles send completionsn for the write bulk data exchange
|
||
operation
|
||
|
||
Arguments:
|
||
|
||
pExchange - pointer to the bulk write data exchange instance.
|
||
|
||
pDataBuffer - the buffer which was transmitted
|
||
|
||
SendCompletionStatus - the completion status
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("send completion Associated Write Data Exchange %lx\n",
|
||
pExchange));
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbWriteBulkDataExchangeFinalize(
|
||
IN OUT struct _SMB_EXCHANGE *pExchange,
|
||
OUT BOOLEAN *pPostRequest)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles the finalization of the write bulk data exchange
|
||
|
||
Arguments:
|
||
|
||
pExchange - pointer to the bulk write data exchange instance.
|
||
|
||
pPostRequest - set to TRUE if the request is to be posted to a worker thread
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (!RxShouldPostCompletion()) {
|
||
PSMB_WRITE_BULK_DATA_EXCHANGE pWriteBulkDataExchange;
|
||
|
||
pWriteBulkDataExchange = (PSMB_WRITE_BULK_DATA_EXCHANGE)pExchange;
|
||
|
||
RxDbgTrace(
|
||
0,
|
||
Dbg,
|
||
("Finalizing Associated Write Data Exchange %lx\n",
|
||
pWriteBulkDataExchange));
|
||
|
||
MmPrepareMdlForReuse(
|
||
pWriteBulkDataExchange->pHeaderMdl);
|
||
|
||
MmPrepareMdlForReuse(
|
||
pWriteBulkDataExchange->pDataMdl);
|
||
|
||
ClearFlag(
|
||
pWriteBulkDataExchange->SmbCeFlags,
|
||
(SMBCE_EXCHANGE_MID_VALID | SMBCE_EXCHANGE_RETAIN_MID));
|
||
|
||
SmbCeDiscardExchange(pExchange);
|
||
|
||
*pPostRequest = FALSE;
|
||
} else {
|
||
*pPostRequest = TRUE;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
SMB_EXCHANGE_DISPATCH_VECTOR
|
||
WriteBulkDataExchangeDispatchVector =
|
||
{
|
||
MRxSmbWriteBulkDataExchangeStart,
|
||
NULL,
|
||
NULL,
|
||
MRxSmbWriteBulkDataExchangeSendCompletionHandler,
|
||
MRxSmbWriteBulkDataExchangeFinalize,
|
||
NULL
|
||
};
|
||
|
||
|
||
|
||
|