VOID NTAPI TransferPacketRetryTimerDpc(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PTRANSFER_PACKET pkt = (PTRANSFER_PACKET)DeferredContext; SubmitTransferPacket(pkt); }
VOID TransferPacketRetryTimerDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PTRANSFER_PACKET pkt; PDEVICE_OBJECT fdo; PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; _Analysis_assume_(DeferredContext != NULL); pkt = (PTRANSFER_PACKET)DeferredContext; fdo = pkt->Fdo; fdoExtension = fdo->DeviceExtension; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2); /* * Sometimes the port driver can allocates a new 'sense' buffer * to report transfer errors, e.g. when the default sense buffer * is too small. If so, it is up to us to free it. * Now that we're done using the sense info, free it if appropriate. * Then clear the sense buffer so it doesn't pollute future errors returned in this packet. */ if (PORT_ALLOCATED_SENSE_EX(fdoExtension, pkt->Srb)) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "Freeing port-allocated sense buffer for pkt %ph.", pkt)); FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExtension, pkt->Srb); SrbSetSenseInfoBuffer(pkt->Srb, &pkt->SrbErrorSenseData); SrbSetSenseInfoBufferLength(pkt->Srb, sizeof(pkt->SrbErrorSenseData)); } else { NT_ASSERT(SrbGetSenseInfoBuffer(pkt->Srb) == &pkt->SrbErrorSenseData); NT_ASSERT(SrbGetSenseInfoBufferLength(pkt->Srb) <= sizeof(pkt->SrbErrorSenseData)); } RtlZeroMemory(&pkt->SrbErrorSenseData, sizeof(pkt->SrbErrorSenseData)); SubmitTransferPacket(pkt); }
VOID TransferPacketRetryTimerDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PTRANSFER_PACKET pkt; _Analysis_assume_(DeferredContext != NULL); pkt = (PTRANSFER_PACKET)DeferredContext; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2); SubmitTransferPacket(pkt); }
/* * 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; }
/* * BUGBUG RESTORE * This is a new implementation of the function that doesn't thrash memory * or depend on the srbLookasideList. * HOWEVER, it seems to cause pagefile initialization to fail during boot * for some reason. Need to resolve this before switching to this function. */ NTSTATUS NTAPI ClasspEjectionControl( IN PDEVICE_OBJECT Fdo, IN PIRP Irp, IN MEDIA_LOCK_TYPE LockType, IN BOOLEAN Lock ) { PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; PFILE_OBJECT_EXTENSION fsContext; BOOLEAN fileHandleOk = TRUE; BOOLEAN countChanged = FALSE; NTSTATUS status; PAGED_CODE(); status = KeWaitForSingleObject( &fdoExt->EjectSynchronizationEvent, UserRequest, UserMode, FALSE, NULL); ASSERT(status == STATUS_SUCCESS); /* * If this is a "secured" request, we have to make sure * that the file handle is valid. */ if (LockType == SecureMediaLock){ PIO_STACK_LOCATION thisSp = IoGetCurrentIrpStackLocation(Irp); /* * Make sure that the file object we are supplied has a * proper FsContext before we try doing a secured lock. */ if (thisSp->FileObject){ PCOMMON_DEVICE_EXTENSION commonExt = (PCOMMON_DEVICE_EXTENSION)fdoExt; fsContext = ClasspGetFsContext(commonExt, thisSp->FileObject); } else { fsContext = NULL; } if (!fsContext){ ASSERT(fsContext); fileHandleOk = FALSE; } } if (fileHandleOk){ /* * Adjust the lock counts and make sure they make sense. */ status = STATUS_SUCCESS; if (Lock){ switch(LockType) { case SimpleMediaLock: fdoExt->LockCount++; countChanged = TRUE; break; case SecureMediaLock: fsContext->LockCount++; fdoExt->ProtectedLockCount++; countChanged = TRUE; break; case InternalMediaLock: fdoExt->InternalLockCount++; countChanged = TRUE; break; } } else { /* * This is an unlock command. If it's a secured one then make sure * the caller has a lock outstanding or return an error. */ switch (LockType){ case SimpleMediaLock: if (fdoExt->LockCount > 0){ fdoExt->LockCount--; countChanged = TRUE; } else { ASSERT(fdoExt->LockCount > 0); status = STATUS_INTERNAL_ERROR; } break; case SecureMediaLock: if (fsContext->LockCount > 0){ ASSERT(fdoExt->ProtectedLockCount > 0); fsContext->LockCount--; fdoExt->ProtectedLockCount--; countChanged = TRUE; } else { ASSERT(fsContext->LockCount > 0); status = STATUS_INVALID_DEVICE_STATE; } break; case InternalMediaLock: ASSERT(fdoExt->InternalLockCount > 0); fdoExt->InternalLockCount--; countChanged = TRUE; break; } } if (NT_SUCCESS(status)){ /* * We only send an unlock command to the drive if * all the lock counts have dropped to zero. */ if (!Lock && (fdoExt->ProtectedLockCount || fdoExt->InternalLockCount || fdoExt->LockCount)){ /* * The lock count is still positive, so don't unlock yet. */ status = STATUS_SUCCESS; } else if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { /* * The device isn't removable media. don't send a cmd. */ status = STATUS_SUCCESS; } else { TRANSFER_PACKET *pkt; pkt = DequeueFreeTransferPacket(Fdo, TRUE); if (pkt){ KEVENT event; /* * Store the number of packets servicing the irp (one) * inside the original IRP. It will be used to counted down * to zero when the packet completes. * Initialize the original IRP's status to success. * If the packet fails, we will set it to the error status. */ Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1); Irp->IoStatus.Status = STATUS_SUCCESS; /* * Set this up as a SYNCHRONOUS transfer, submit it, * and wait for the packet to complete. The result * status will be written to the original irp. */ KeInitializeEvent(&event, SynchronizationEvent, FALSE); SetupEjectionTransferPacket(pkt, Lock, &event, Irp); SubmitTransferPacket(pkt); KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = Irp->IoStatus.Status; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } } } else { status = STATUS_INVALID_PARAMETER; } if (!NT_SUCCESS(status) && countChanged) { // // have to revert to previous counts if the // lock/unlock operation actually failed. // if(Lock) { switch(LockType) { case SimpleMediaLock: { FdoExtension->LockCount--; break; } case SecureMediaLock: { fsContext->LockCount--; FdoExtension->ProtectedLockCount--; break; } case InternalMediaLock: { FdoExtension->InternalLockCount--; break; } } } else { switch(LockType) { case SimpleMediaLock: { FdoExtension->LockCount++; break; } case SecureMediaLock: { fsContext->LockCount++; FdoExtension->ProtectedLockCount++; break; } case InternalMediaLock: { FdoExtension->InternalLockCount++; break; } } } } KeSetEvent(&fdoExt->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE); return status; }