/* * StepLowMemRetry * * During extreme low-memory stress, this function retries * a packet in small one-page chunks, sent serially. * * Returns TRUE iff the packet is done. */ BOOLEAN NTAPI StepLowMemRetry(PTRANSFER_PACKET Pkt) { BOOLEAN packetDone; if (Pkt->LowMemRetry_remainingBufLen == 0){ packetDone = TRUE; } else { ULONG thisChunkLen; ULONG bytesToNextPageBoundary; /* * Make sure the little chunk we send is <= a page length * AND that it does not cross any page boundaries. */ bytesToNextPageBoundary = PAGE_SIZE-(ULONG)((ULONG_PTR)Pkt->LowMemRetry_remainingBufPtr%PAGE_SIZE); thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, bytesToNextPageBoundary); /* * Set up the transfer packet for the new little chunk. * This will reset numRetries so that we retry each chunk as required. */ SetupReadWriteTransferPacket(Pkt, Pkt->LowMemRetry_remainingBufPtr, thisChunkLen, Pkt->LowMemRetry_nextChunkTargetLocation, Pkt->OriginalIrp); Pkt->LowMemRetry_remainingBufPtr += thisChunkLen; Pkt->LowMemRetry_remainingBufLen -= thisChunkLen; Pkt->LowMemRetry_nextChunkTargetLocation.QuadPart += thisChunkLen; SubmitTransferPacket(Pkt); packetDone = FALSE; } return packetDone; }
/* * StepLowMemRetry * * During extreme low-memory stress, this function retries * a packet in small one-page chunks, sent serially. * * Returns TRUE iff the packet is done. */ BOOLEAN StepLowMemRetry(PTRANSFER_PACKET Pkt) { BOOLEAN packetDone; if (Pkt->LowMemRetry_remainingBufLen == 0){ packetDone = TRUE; } else { ULONG thisChunkLen; if (Pkt->DriverUsesStartIO) { /* * Need the fdoData for the HwMaxXferLen */ PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension; PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; /* * Need the adapterDesc to limit transfers based on byte count */ PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension; PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExtension->PartitionZeroExtension->AdapterDescriptor; ULONG hwMaxXferLen; /* * special case: StartIO-based writing must stay serialized for performance * and proper operations (i.e. sequential writing mode). If need more than * one transfer to perform this operation, and it's a StartIO-based driver * (such as CDROM), then just use a single packet and use the retry logic * that's already built-in to the packet engine. Note that low-mem retry * cannot be used directly because some write methods do not work if the * writes are only PAGE_SIZE (i.e. packet writing may corrupt data). */ NT_ASSERT(!Pkt->InLowMemRetry); /* * We precomputed fdoData->HwMaxXferLen using (MaximumPhysicalPages-1). * If the buffer is page-aligned, that's one less page crossing so we can add the page back in. * Note: adapters that return MaximumPhysicalPages=0x10 depend on this to * transfer aligned 64K requests in one piece. * Also note: make sure adding PAGE_SIZE back in doesn't wrap to zero. */ if (((ULONG_PTR)(Pkt->LowMemRetry_remainingBufPtr) & (PAGE_SIZE-1)) || (fdoData->HwMaxXferLen > 0xffffffff-PAGE_SIZE)){ hwMaxXferLen = fdoData->HwMaxXferLen; } else { NT_ASSERT((PAGE_SIZE%fdoExt->DiskGeometry.BytesPerSector) == 0); hwMaxXferLen = min(fdoData->HwMaxXferLen+PAGE_SIZE, adapterDesc->MaximumTransferLength); } thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, hwMaxXferLen); } else { /* * Make sure the little chunk we send is <= a page length * AND that it does not cross any page boundaries. */ ULONG bytesToNextPageBoundary; bytesToNextPageBoundary = PAGE_SIZE-(ULONG)((ULONG_PTR)Pkt->LowMemRetry_remainingBufPtr%PAGE_SIZE); thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, bytesToNextPageBoundary); NT_ASSERT(Pkt->InLowMemRetry); } /* * Set up the transfer packet for the new little chunk. * This will reset numRetries so that we retry each chunk as required. */ SetupReadWriteTransferPacket(Pkt, Pkt->LowMemRetry_remainingBufPtr, thisChunkLen, Pkt->LowMemRetry_nextChunkTargetLocation, Pkt->OriginalIrp); Pkt->LowMemRetry_remainingBufPtr += thisChunkLen; Pkt->LowMemRetry_remainingBufLen -= thisChunkLen; Pkt->LowMemRetry_nextChunkTargetLocation.QuadPart += thisChunkLen; // // When running in low-memory stress, always use a partial MDL. // This allows lower drivers to potentially map a smaller buffer. // Pkt->UsePartialMdl = TRUE; TransferPacketQueueRetryDpc(Pkt); packetDone = FALSE; } return packetDone; }