Exemplo n.º 1
0
/*
 *  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;
}
Exemplo n.º 2
0
Arquivo: retry.c Projeto: uri247/wdk80
/*
 *  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;
}