mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2413 lines
62 KiB
2413 lines
62 KiB
/*++
|
|
|
|
Copyright (C) 1991-5 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
redist.cxx
|
|
|
|
Abstract:
|
|
|
|
This module contains the code specific to redistributions for the fault
|
|
tolerance driver.
|
|
|
|
Author:
|
|
|
|
Norbert Kusters 6-Feb-1997
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
extern "C" {
|
|
#include <ntddk.h>
|
|
}
|
|
|
|
#include <ftdisk.h>
|
|
|
|
class PROPOGATE_CHANGES_WORK_ITEM : public WORK_QUEUE_ITEM {
|
|
|
|
public:
|
|
|
|
PREDISTRIBUTION Redistribution;
|
|
FT_COMPLETION_ROUTINE CompletionRoutine;
|
|
PVOID Context;
|
|
|
|
};
|
|
|
|
typedef PROPOGATE_CHANGES_WORK_ITEM *PPROPOGATE_CHANGES_WORK_ITEM;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma code_seg("PAGE")
|
|
#endif
|
|
|
|
NTSTATUS
|
|
REDISTRIBUTION::Initialize(
|
|
IN OUT PROOT_EXTENSION RootExtension,
|
|
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
|
IN OUT PFT_VOLUME* VolumeArray,
|
|
IN USHORT ArraySize,
|
|
IN PVOID ConfigInfo,
|
|
IN PVOID StateInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize routine for FT_VOLUME of type REDISTRIBUTION.
|
|
|
|
Arguments:
|
|
|
|
RootExtension - Supplies the root device extension.
|
|
|
|
LogicalDiskId - Supplies the logical disk id for this volume.
|
|
|
|
VolumeArray - Supplies the array of volumes for this volume set.
|
|
|
|
ArraySize - Supplies the number of volumes in the volume array.
|
|
|
|
ConfigInfo - Supplies the configuration information.
|
|
|
|
StateInfo - Supplies the state information.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN oneGood;
|
|
USHORT i;
|
|
NTSTATUS status;
|
|
PFT_REDISTRIBUTION_CONFIGURATION_INFORMATION configInfo;
|
|
LONGLONG firstRowSize;
|
|
LONGLONG secondRowSize;
|
|
LONGLONG numRows;
|
|
LONGLONG tmpNumRows;
|
|
|
|
if (ArraySize != 2) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
oneGood = FALSE;
|
|
for (i = 0; i < ArraySize; i++) {
|
|
if (VolumeArray[i]) {
|
|
oneGood = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!oneGood) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
status = COMPOSITE_FT_VOLUME::Initialize(RootExtension, LogicalDiskId,
|
|
VolumeArray, ArraySize,
|
|
ConfigInfo, StateInfo);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
configInfo = (PFT_REDISTRIBUTION_CONFIGURATION_INFORMATION) ConfigInfo;
|
|
_stripeSize = configInfo->StripeSize;
|
|
if (_stripeSize < QuerySectorSize()) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
for (i = 0; _stripeSize%2 == 0; i++) {
|
|
_stripeSize /= 2;
|
|
}
|
|
if (_stripeSize != 1) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
_stripeSize = configInfo->StripeSize;
|
|
|
|
if( !configInfo->FirstMemberWidth || !configInfo->SecondMemberWidth) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
_firstWidth = configInfo->FirstMemberWidth;
|
|
_totalWidth = _firstWidth + configInfo->SecondMemberWidth;
|
|
|
|
if (VolumeArray[0]) {
|
|
_firstSize = VolumeArray[0]->QueryVolumeSize();
|
|
} else {
|
|
_firstSize = 0;
|
|
}
|
|
|
|
if (_firstSize && VolumeArray[1]) {
|
|
firstRowSize = _firstWidth*_stripeSize;
|
|
numRows = _firstSize/firstRowSize;
|
|
secondRowSize = configInfo->SecondMemberWidth*_stripeSize;
|
|
tmpNumRows = VolumeArray[1]->QueryVolumeSize()/secondRowSize;
|
|
if (tmpNumRows < numRows) {
|
|
numRows = tmpNumRows;
|
|
}
|
|
_totalSize = numRows*_totalWidth*_stripeSize;
|
|
if (_totalSize < _firstSize) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
_totalSize = 0;
|
|
}
|
|
_syncOk = TRUE;
|
|
_stopSyncs = FALSE;
|
|
|
|
RtlCopyMemory(&_state, StateInfo, sizeof(_state));
|
|
|
|
if (_state.BytesRedistributed < _firstSize) {
|
|
_redistributionComplete = FALSE;
|
|
} else {
|
|
_redistributionComplete = TRUE;
|
|
}
|
|
|
|
status = _overlappedIoManager.Initialize(0);
|
|
|
|
return status;
|
|
}
|
|
|
|
FT_LOGICAL_DISK_TYPE
|
|
REDISTRIBUTION::QueryLogicalDiskType(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the type of the logical disk.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The type of the logical disk.
|
|
|
|
--*/
|
|
|
|
{
|
|
return FtRedistribution;
|
|
}
|
|
|
|
NTSTATUS
|
|
REDISTRIBUTION::CheckIo(
|
|
OUT PBOOLEAN IsIoOk
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns whether or not IO is possible on the given
|
|
logical disk.
|
|
|
|
Arguments:
|
|
|
|
IsIoOk - Returns the state of IO.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT n, i;
|
|
PFT_VOLUME vol;
|
|
NTSTATUS status;
|
|
|
|
n = QueryNumMembers();
|
|
for (i = 0; i < n; i++) {
|
|
vol = GetMemberUnprotected(i);
|
|
if (!vol) {
|
|
*IsIoOk = FALSE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
status = vol->CheckIo(IsIoOk);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
if (!(*IsIoOk)) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma code_seg("PAGELK")
|
|
#endif
|
|
|
|
REDISTRIBUTION::~REDISTRIBUTION(
|
|
)
|
|
|
|
{
|
|
}
|
|
|
|
VOID
|
|
RedistributionTwoPartCompletionRoutine(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the completion of a two part operation.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP transferPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PREDISTRIBUTION_LOCK_TP lockPacket = (PREDISTRIBUTION_LOCK_TP) transferPacket->MasterPacket;
|
|
PTRANSFER_PACKET masterPacket = lockPacket->MasterPacket;
|
|
NTSTATUS status = transferPacket->IoStatus.Status;
|
|
KIRQL irql;
|
|
LONG count;
|
|
|
|
KeAcquireSpinLock(&lockPacket->SpinLock, &irql);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if (NT_SUCCESS(lockPacket->IoStatus.Status)) {
|
|
lockPacket->IoStatus.Information +=
|
|
transferPacket->IoStatus.Information;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (FtpIsWorseStatus(status, lockPacket->IoStatus.Status)) {
|
|
lockPacket->IoStatus.Status = status;
|
|
}
|
|
}
|
|
|
|
count = --lockPacket->RefCount;
|
|
|
|
KeReleaseSpinLock(&lockPacket->SpinLock, irql);
|
|
|
|
delete transferPacket;
|
|
|
|
if (!count) {
|
|
masterPacket->IoStatus = lockPacket->IoStatus;
|
|
delete lockPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
RedistributionRegionLockCompletion(
|
|
IN OUT PTRANSFER_PACKET LockPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the completion of a region lock operation.
|
|
|
|
Arguments:
|
|
|
|
LockPacket - Supplies the lock packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_LOCK_TP lockPacket = (PREDISTRIBUTION_LOCK_TP) LockPacket;
|
|
PREDISTRIBUTION t = lockPacket->Redistribution;
|
|
PTRANSFER_PACKET masterPacket = lockPacket->MasterPacket;
|
|
KIRQL irql;
|
|
LONGLONG bytesRedistributed;
|
|
LONGLONG redistOffset, regularOffset;
|
|
ULONG redistLength, regularLength;
|
|
PREDISTRIBUTION_TP redistPacket, regularPacket;
|
|
PCHAR vp;
|
|
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
bytesRedistributed = t->_state.BytesRedistributed;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
|
|
if (lockPacket->Offset < bytesRedistributed) {
|
|
redistOffset = lockPacket->Offset;
|
|
redistLength = lockPacket->Length;
|
|
if (redistOffset + redistLength > bytesRedistributed) {
|
|
redistLength = (ULONG) (bytesRedistributed - redistOffset);
|
|
}
|
|
} else {
|
|
redistLength = 0;
|
|
}
|
|
|
|
if (redistLength < lockPacket->Length) {
|
|
regularLength = lockPacket->Length - redistLength;
|
|
regularOffset = lockPacket->Offset + redistLength;
|
|
} else {
|
|
regularLength = 0;
|
|
}
|
|
|
|
KeInitializeSpinLock(&lockPacket->SpinLock);
|
|
lockPacket->IoStatus.Status = STATUS_SUCCESS;
|
|
lockPacket->IoStatus.Information = 0;
|
|
lockPacket->RefCount = 0;
|
|
|
|
if (lockPacket->Mdl && redistLength && regularLength) {
|
|
vp = (PCHAR) MmGetMdlVirtualAddress(lockPacket->Mdl);
|
|
}
|
|
|
|
if (redistLength) {
|
|
lockPacket->RefCount++;
|
|
redistPacket = new REDISTRIBUTION_TP;
|
|
if (!redistPacket) {
|
|
delete lockPacket;
|
|
masterPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
masterPacket->IoStatus.Information = 0;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
if (regularLength) {
|
|
if (lockPacket->Mdl) {
|
|
if (redistPacket->AllocateMdl(vp, redistLength)) {
|
|
IoBuildPartialMdl(lockPacket->Mdl, redistPacket->Mdl,
|
|
vp, redistLength);
|
|
} else {
|
|
delete redistPacket;
|
|
delete lockPacket;
|
|
masterPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
masterPacket->IoStatus.Information = 0;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
} else {
|
|
redistPacket->Mdl = lockPacket->Mdl;
|
|
}
|
|
} else {
|
|
redistPacket->Mdl = lockPacket->Mdl;
|
|
}
|
|
redistPacket->Length = redistLength;
|
|
redistPacket->Offset = redistOffset;
|
|
redistPacket->CompletionRoutine = RedistributionTwoPartCompletionRoutine;
|
|
redistPacket->TargetVolume = t;
|
|
redistPacket->Thread = lockPacket->Thread;
|
|
redistPacket->IrpFlags = lockPacket->IrpFlags;
|
|
redistPacket->ReadPacket = lockPacket->ReadPacket;
|
|
redistPacket->MasterPacket = lockPacket;
|
|
redistPacket->Redistribution = t;
|
|
redistPacket->WhichMember = 0;
|
|
}
|
|
|
|
if (regularLength) {
|
|
lockPacket->RefCount++;
|
|
regularPacket = new REDISTRIBUTION_TP;
|
|
if (!regularPacket) {
|
|
if (redistLength) {
|
|
delete redistPacket;
|
|
}
|
|
delete lockPacket;
|
|
masterPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
masterPacket->IoStatus.Information = 0;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
if (redistLength) {
|
|
if (lockPacket->Mdl) {
|
|
if (regularPacket->AllocateMdl(vp, regularLength)) {
|
|
IoBuildPartialMdl(lockPacket->Mdl, regularPacket->Mdl,
|
|
vp, regularLength);
|
|
} else {
|
|
if (redistLength) {
|
|
delete redistPacket;
|
|
}
|
|
delete regularPacket;
|
|
delete lockPacket;
|
|
masterPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
masterPacket->IoStatus.Information = 0;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
} else {
|
|
regularPacket->Mdl = lockPacket->Mdl;
|
|
}
|
|
} else {
|
|
regularPacket->Mdl = lockPacket->Mdl;
|
|
}
|
|
regularPacket->Length = regularLength;
|
|
regularPacket->Offset = regularOffset;
|
|
regularPacket->CompletionRoutine = RedistributionTwoPartCompletionRoutine;
|
|
regularPacket->TargetVolume = t->GetMemberUnprotected(0);
|
|
regularPacket->Thread = lockPacket->Thread;
|
|
regularPacket->IrpFlags = lockPacket->IrpFlags;
|
|
regularPacket->ReadPacket = lockPacket->ReadPacket;
|
|
regularPacket->MasterPacket = lockPacket;
|
|
regularPacket->Redistribution = t;
|
|
regularPacket->WhichMember = 0;
|
|
}
|
|
|
|
if (redistLength) {
|
|
t->RedistributeTransfer(redistPacket);
|
|
}
|
|
|
|
if (regularLength) {
|
|
TRANSFER(regularPacket);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::Transfer(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Transfer routine for REDISTRIBUTION type FT_VOLUME. Figure out
|
|
which volumes this request needs to be dispatched to.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_LOCK_TP lockPacket;
|
|
|
|
if (!_redistributionComplete) {
|
|
if (TransferPacket->Offset + TransferPacket->Length > _firstSize) {
|
|
TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
lockPacket = new REDISTRIBUTION_LOCK_TP;
|
|
if (!lockPacket) {
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
lockPacket->Mdl = TransferPacket->Mdl;
|
|
lockPacket->Length = TransferPacket->Length;
|
|
lockPacket->Offset = TransferPacket->Offset;
|
|
lockPacket->CompletionRoutine = RedistributionRegionLockCompletion;
|
|
lockPacket->TargetVolume = TransferPacket->TargetVolume;
|
|
lockPacket->Thread = TransferPacket->Thread;
|
|
lockPacket->IrpFlags = TransferPacket->IrpFlags;
|
|
lockPacket->ReadPacket = TransferPacket->ReadPacket;
|
|
lockPacket->MasterPacket = TransferPacket;
|
|
lockPacket->Redistribution = this;
|
|
|
|
_overlappedIoManager.AcquireIoRegion(lockPacket, TRUE);
|
|
return;
|
|
}
|
|
|
|
if (TransferPacket->Offset + TransferPacket->Length > _totalSize) {
|
|
TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
RedistributeTransfer(TransferPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionReplaceCompletion(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a replace request.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_LOCK_TP transferPacket = (PREDISTRIBUTION_LOCK_TP) TransferPacket;
|
|
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
|
|
|
|
masterPacket->IoStatus = transferPacket->IoStatus;
|
|
delete transferPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionLockReplaceCompletion(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a lock request.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_LOCK_TP transferPacket = (PREDISTRIBUTION_LOCK_TP) TransferPacket;
|
|
PREDISTRIBUTION t = transferPacket->Redistribution;
|
|
KIRQL irql;
|
|
LONGLONG bytesRedistributed;
|
|
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
bytesRedistributed = t->_state.BytesRedistributed;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
|
|
transferPacket->CompletionRoutine = RedistributionReplaceCompletion;
|
|
if (transferPacket->Offset < bytesRedistributed) {
|
|
t->RedistributeReplaceBadSector(transferPacket);
|
|
} else {
|
|
transferPacket->TargetVolume = t->GetMemberUnprotected(0);
|
|
transferPacket->TargetVolume->ReplaceBadSector(transferPacket);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::ReplaceBadSector(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to fix the given bad sector by routing
|
|
the request to the appropriate sub-volume.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_LOCK_TP lockPacket;
|
|
|
|
if (!_redistributionComplete) {
|
|
if (TransferPacket->Offset + TransferPacket->Length > _firstSize) {
|
|
TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
lockPacket = new REDISTRIBUTION_LOCK_TP;
|
|
if (!lockPacket) {
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
lockPacket->Mdl = TransferPacket->Mdl;
|
|
lockPacket->Length = TransferPacket->Length;
|
|
lockPacket->Offset = TransferPacket->Offset;
|
|
lockPacket->CompletionRoutine = RedistributionLockReplaceCompletion;
|
|
lockPacket->TargetVolume = TransferPacket->TargetVolume;
|
|
lockPacket->Thread = TransferPacket->Thread;
|
|
lockPacket->IrpFlags = TransferPacket->IrpFlags;
|
|
lockPacket->ReadPacket = TransferPacket->ReadPacket;
|
|
lockPacket->MasterPacket = TransferPacket;
|
|
lockPacket->Redistribution = this;
|
|
|
|
_overlappedIoManager.AcquireIoRegion(lockPacket, TRUE);
|
|
return;
|
|
}
|
|
|
|
if (TransferPacket->Offset + TransferPacket->Length > _totalSize) {
|
|
TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
RedistributeReplaceBadSector(TransferPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionCompositeVolumeCompletionRoutine(
|
|
IN PVOID Context,
|
|
IN NTSTATUS Status
|
|
)
|
|
|
|
{
|
|
PFT_COMPLETION_ROUTINE_CONTEXT context;
|
|
KIRQL irql;
|
|
LONG count;
|
|
|
|
context = (PFT_COMPLETION_ROUTINE_CONTEXT) Context;
|
|
|
|
KeAcquireSpinLock(&context->SpinLock, &irql);
|
|
if (!NT_SUCCESS(Status) && FtpIsWorseStatus(Status, context->Status)) {
|
|
context->Status = Status;
|
|
}
|
|
count = --context->RefCount;
|
|
KeReleaseSpinLock(&context->SpinLock, irql);
|
|
|
|
if (!count) {
|
|
context->CompletionRoutine(context->Context, STATUS_SUCCESS);
|
|
ExFreePool(context);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
RedistributionSyncPhase6(
|
|
IN OUT PVOID SyncPacket,
|
|
IN NTSTATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for the update state part of a sync.
|
|
|
|
Arguments:
|
|
|
|
SyncPacket - Supplies the transfer packet.
|
|
|
|
Status - Supplies the status.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_SYNC_TP syncPacket = (PREDISTRIBUTION_SYNC_TP) SyncPacket;
|
|
PREDISTRIBUTION_TP ioPacket = &syncPacket->IoPacket;
|
|
PREDISTRIBUTION t = syncPacket->Redistribution;
|
|
KIRQL irql;
|
|
BOOLEAN allDone;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_state.BytesRedistributed -= ioPacket->Length;
|
|
t->_syncOk = TRUE;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
t->_overlappedIoManager.ReleaseIoRegion(syncPacket);
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context,
|
|
STATUS_SUCCESS);
|
|
delete syncPacket;
|
|
return;
|
|
}
|
|
|
|
if (t->_state.BytesRedistributed == t->_firstSize) {
|
|
t->_redistributionComplete = TRUE;
|
|
allDone = TRUE;
|
|
} else {
|
|
allDone = FALSE;
|
|
}
|
|
t->_overlappedIoManager.ReleaseIoRegion(syncPacket);
|
|
|
|
if (allDone) {
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context,
|
|
STATUS_SUCCESS);
|
|
delete syncPacket;
|
|
return;
|
|
}
|
|
|
|
syncPacket->Offset = t->_state.BytesRedistributed;
|
|
|
|
t->_overlappedIoManager.AcquireIoRegion(syncPacket, TRUE);
|
|
}
|
|
|
|
VOID
|
|
RedistributionSyncPhase5(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for the write verify part of a sync.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP ioPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PREDISTRIBUTION_SYNC_TP syncPacket = (PREDISTRIBUTION_SYNC_TP) ioPacket->MasterPacket;
|
|
PREDISTRIBUTION t = syncPacket->Redistribution;
|
|
NTSTATUS status = ioPacket->IoStatus.Status;
|
|
KIRQL irql;
|
|
|
|
if (FsRtlIsTotalDeviceFailure(status)) {
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_syncOk = TRUE;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context,
|
|
status);
|
|
delete syncPacket;
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_syncOk = TRUE;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context, status);
|
|
delete syncPacket;
|
|
FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
|
|
FT_REDISTRIBUTION_ERROR, status, 0);
|
|
return;
|
|
}
|
|
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_state.BytesRedistributed += ioPacket->Length;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
|
|
t->PropogateStateChanges(RedistributionSyncPhase6, syncPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionSyncPhase4(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for the verify write part of a sync.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP ioPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PREDISTRIBUTION_SYNC_TP syncPacket = (PREDISTRIBUTION_SYNC_TP) ioPacket->MasterPacket;
|
|
PREDISTRIBUTION t = syncPacket->Redistribution;
|
|
NTSTATUS status = ioPacket->IoStatus.Status;
|
|
KIRQL irql;
|
|
|
|
if (FsRtlIsTotalDeviceFailure(status)) {
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_syncOk = TRUE;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context,
|
|
status);
|
|
delete syncPacket;
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ioPacket->CompletionRoutine = RedistributionSyncPhase5;
|
|
t->CarefulWrite(ioPacket);
|
|
return;
|
|
}
|
|
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_state.BytesRedistributed += ioPacket->Length;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
|
|
t->PropogateStateChanges(RedistributionSyncPhase6, syncPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionSyncPhase3(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for the initial write part of a sync.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP ioPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PREDISTRIBUTION_SYNC_TP syncPacket = (PREDISTRIBUTION_SYNC_TP) ioPacket->MasterPacket;
|
|
PREDISTRIBUTION t = syncPacket->Redistribution;
|
|
NTSTATUS status = ioPacket->IoStatus.Status;
|
|
KIRQL irql;
|
|
|
|
if (FsRtlIsTotalDeviceFailure(status)) {
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_syncOk = TRUE;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context,
|
|
status);
|
|
delete syncPacket;
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ioPacket->CompletionRoutine = RedistributionSyncPhase5;
|
|
t->CarefulWrite(ioPacket);
|
|
return;
|
|
}
|
|
|
|
ioPacket->CompletionRoutine = RedistributionSyncPhase4;
|
|
t->VerifyWrite(ioPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionSyncPhase2(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for the read part of a sync.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP ioPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PREDISTRIBUTION_SYNC_TP syncPacket = (PREDISTRIBUTION_SYNC_TP) ioPacket->MasterPacket;
|
|
PREDISTRIBUTION t = syncPacket->Redistribution;
|
|
NTSTATUS status = ioPacket->IoStatus.Status;
|
|
LONGLONG rowSize, rowNum, rowOffset, firstSize;
|
|
KIRQL irql;
|
|
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
if (t->_stopSyncs) {
|
|
t->_syncOk = TRUE;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context,
|
|
STATUS_SUCCESS);
|
|
delete syncPacket;
|
|
return;
|
|
}
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
|
|
if (FsRtlIsTotalDeviceFailure(status)) {
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
t->_syncOk = TRUE;
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
RedistributionCompositeVolumeCompletionRoutine(syncPacket->Context,
|
|
status);
|
|
delete syncPacket;
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
t->MaxTransfer(ioPacket);
|
|
return;
|
|
}
|
|
|
|
rowSize = t->_totalWidth*t->_stripeSize;
|
|
rowNum = ioPacket->Offset/rowSize;
|
|
rowOffset = ioPacket->Offset%rowSize;
|
|
firstSize = t->_firstWidth*t->_stripeSize;
|
|
|
|
ioPacket->CompletionRoutine = RedistributionSyncPhase3;
|
|
ioPacket->ReadPacket = FALSE;
|
|
|
|
if (rowOffset < firstSize) {
|
|
ioPacket->Offset = rowNum*firstSize + rowOffset;
|
|
} else {
|
|
ioPacket->Offset = rowNum*(rowSize - firstSize) + rowOffset - firstSize;
|
|
ioPacket->TargetVolume = t->GetMemberUnprotected(1);
|
|
ioPacket->WhichMember = 1;
|
|
}
|
|
|
|
TRANSFER(ioPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionSyncPhase1(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for the lock part of a sync.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_SYNC_TP syncPacket = (PREDISTRIBUTION_SYNC_TP) TransferPacket;
|
|
PREDISTRIBUTION t = syncPacket->Redistribution;
|
|
PREDISTRIBUTION_TP packet = &syncPacket->IoPacket;
|
|
|
|
packet->Offset = t->_state.BytesRedistributed;
|
|
if (packet->Offset + packet->Length > t->_firstSize) {
|
|
packet->Length = (ULONG) (t->_firstSize - packet->Offset);
|
|
}
|
|
|
|
packet->CompletionRoutine = RedistributionSyncPhase2;
|
|
packet->TargetVolume = t->GetMemberUnprotected(0);
|
|
packet->Thread = PsGetCurrentThread();
|
|
packet->ReadPacket = TRUE;
|
|
packet->WhichMember = 0;
|
|
|
|
TRANSFER(packet);
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::StartSyncOperations(
|
|
IN BOOLEAN RegenerateOrphans,
|
|
IN FT_COMPLETION_ROUTINE CompletionRoutine,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts off the redistribution of the data.
|
|
|
|
Arguments:
|
|
|
|
RegenerateOrphans - Supplies whether or not to try and regenerate
|
|
orphaned members.
|
|
|
|
CompletionRoutine - Supplies the completion routine.
|
|
|
|
Context - Supplies the context for the completion routine.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFT_COMPLETION_ROUTINE_CONTEXT context;
|
|
PREDISTRIBUTION_SYNC_TP syncPacket;
|
|
KIRQL irql;
|
|
PREDISTRIBUTION_TP packet;
|
|
|
|
if (_redistributionComplete) {
|
|
COMPOSITE_FT_VOLUME::StartSyncOperations(RegenerateOrphans,
|
|
CompletionRoutine, Context);
|
|
return;
|
|
}
|
|
|
|
context = (PFT_COMPLETION_ROUTINE_CONTEXT)
|
|
ExAllocatePool(NonPagedPool,
|
|
sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
|
|
if (!context) {
|
|
CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
|
|
return;
|
|
}
|
|
|
|
syncPacket = new REDISTRIBUTION_SYNC_TP;
|
|
if (!syncPacket) {
|
|
ExFreePool(context);
|
|
CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
|
|
return;
|
|
}
|
|
|
|
if (!syncPacket->IoPacket.AllocateMdl(_stripeSize)) {
|
|
delete syncPacket;
|
|
ExFreePool(context);
|
|
CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
|
|
return;
|
|
}
|
|
|
|
KeInitializeSpinLock(&context->SpinLock);
|
|
context->Status = STATUS_SUCCESS;
|
|
context->RefCount = 2;
|
|
context->CompletionRoutine = CompletionRoutine;
|
|
context->Context = Context;
|
|
context->ParentVolume = this;
|
|
|
|
COMPOSITE_FT_VOLUME::StartSyncOperations(
|
|
RegenerateOrphans, RedistributionCompositeVolumeCompletionRoutine,
|
|
context);
|
|
|
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|
if (_syncOk) {
|
|
_syncOk = FALSE;
|
|
_stopSyncs = FALSE;
|
|
} else {
|
|
KeReleaseSpinLock(&_spinLock, irql);
|
|
RedistributionCompositeVolumeCompletionRoutine(context, STATUS_SUCCESS);
|
|
return;
|
|
}
|
|
KeReleaseSpinLock(&_spinLock, irql);
|
|
|
|
syncPacket->Mdl = NULL;
|
|
syncPacket->Offset = _state.BytesRedistributed;
|
|
syncPacket->Length = _stripeSize;
|
|
syncPacket->CompletionRoutine = RedistributionSyncPhase1;
|
|
syncPacket->TargetVolume = this;
|
|
syncPacket->Thread = PsGetCurrentThread();
|
|
syncPacket->IrpFlags = SL_OVERRIDE_VERIFY_VOLUME;
|
|
syncPacket->ReadPacket = TRUE;
|
|
syncPacket->Context = context;
|
|
syncPacket->Redistribution = this;
|
|
|
|
packet = &syncPacket->IoPacket;
|
|
packet->Length = _stripeSize;
|
|
packet->IrpFlags = SL_OVERRIDE_VERIFY_VOLUME;
|
|
packet->MasterPacket = syncPacket;
|
|
packet->Redistribution = this;
|
|
|
|
_overlappedIoManager.AcquireIoRegion(syncPacket, TRUE);
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::StopSyncOperations(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stops all sync operations.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL irql;
|
|
|
|
COMPOSITE_FT_VOLUME::StopSyncOperations();
|
|
|
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|
_stopSyncs = TRUE;
|
|
KeReleaseSpinLock(&_spinLock, irql);
|
|
}
|
|
|
|
LONGLONG
|
|
REDISTRIBUTION::QueryVolumeSize(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the number of bytes on the entire volume.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The volume size in bytes.
|
|
|
|
--*/
|
|
|
|
{
|
|
return _redistributionComplete ? _totalSize : _firstSize;
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::CompleteNotification(
|
|
IN BOOLEAN IoPending
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to notify the volume that it is complete and
|
|
to therefore prepare for incoming requests.
|
|
|
|
Arguments:
|
|
|
|
IoPending - Supplies whether or not there is IO pending.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONGLONG firstRowSize, numRows, secondRowSize, tmpNumRows;
|
|
|
|
COMPOSITE_FT_VOLUME::CompleteNotification(IoPending);
|
|
|
|
_firstSize = GetMember(0)->QueryVolumeSize();
|
|
firstRowSize = _firstWidth*_stripeSize;
|
|
numRows = _firstSize/firstRowSize;
|
|
secondRowSize = (_totalWidth - _firstWidth)*_stripeSize;
|
|
tmpNumRows = GetMember(1)->QueryVolumeSize()/secondRowSize;
|
|
if (tmpNumRows < numRows) {
|
|
numRows = tmpNumRows;
|
|
}
|
|
_totalSize = numRows*_totalWidth*_stripeSize;
|
|
|
|
if (_state.BytesRedistributed >= _firstSize) {
|
|
_redistributionComplete = TRUE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::NewStateArrival(
|
|
IN PVOID NewStateInstance
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the new state instance arrival combined with its
|
|
current state to come up with the new current state for the volume.
|
|
If the two states cannot be reconciled then this routine returns FALSE
|
|
indicating that the volume is invalid and should be broken into its
|
|
constituant parts.
|
|
|
|
Arguments:
|
|
|
|
NewStateInstance - Supplies the new state instance.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN changed = FALSE;
|
|
PFT_REDISTRIBUTION_STATE_INFORMATION state;
|
|
|
|
state = (PFT_REDISTRIBUTION_STATE_INFORMATION) NewStateInstance;
|
|
if (state->BytesRedistributed > _state.BytesRedistributed) {
|
|
_state.BytesRedistributed = state->BytesRedistributed;
|
|
changed = TRUE;
|
|
}
|
|
|
|
if (changed) {
|
|
PropogateStateChanges(NULL, NULL);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
RedistributionTransferCompletionRoutine(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for REDISTRIBUTION::RedistributionDispatch.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP transferPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
|
|
NTSTATUS status = transferPacket->IoStatus.Status;
|
|
KIRQL irql;
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
|
|
if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
|
|
masterPacket->IoStatus.Status = status;
|
|
}
|
|
KeReleaseSpinLock(&masterPacket->SpinLock, irql);
|
|
}
|
|
|
|
delete transferPacket;
|
|
|
|
if (!InterlockedDecrement(&masterPacket->RefCount)) {
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::RedistributeTransfer(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine launches the given transfer packet using the new
|
|
redistributed data allocation scheme.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet to launch.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONGLONG begin, end;
|
|
LONGLONG rowSize, firstSize, rowBegin, rowOffsetBegin, rowEnd, rowOffsetEnd;
|
|
ULONG numRequests, i, numRows;
|
|
PCHAR vp;
|
|
LIST_ENTRY q;
|
|
LONGLONG off, off2;
|
|
ULONG len, len2;
|
|
USHORT whichMember;
|
|
BOOLEAN two;
|
|
PREDISTRIBUTION_TP p;
|
|
PLIST_ENTRY l;
|
|
|
|
begin = TransferPacket->Offset;
|
|
end = TransferPacket->Offset + TransferPacket->Length;
|
|
rowSize = _totalWidth*_stripeSize;
|
|
rowBegin = begin/rowSize;
|
|
rowOffsetBegin = begin%rowSize;
|
|
rowEnd = end/rowSize;
|
|
rowOffsetEnd = end%rowSize;
|
|
firstSize = _firstWidth*_stripeSize;
|
|
|
|
if (TransferPacket->Mdl) {
|
|
vp = (PCHAR) MmGetMdlVirtualAddress(TransferPacket->Mdl);
|
|
}
|
|
InitializeListHead(&q);
|
|
numRows = (ULONG) (rowEnd - rowBegin + 1);
|
|
numRequests = 0;
|
|
for (i = 0; i < numRows; i++) {
|
|
|
|
if (i == 0) {
|
|
if (numRows == 1) {
|
|
if (rowOffsetBegin < firstSize) {
|
|
if (rowOffsetEnd > firstSize) {
|
|
two = TRUE;
|
|
whichMember = 0;
|
|
off = rowBegin*firstSize + rowOffsetBegin;
|
|
len = (ULONG) (firstSize - rowOffsetBegin);
|
|
off2 = rowBegin*(rowSize - firstSize);
|
|
len2 = (ULONG) (rowOffsetEnd - firstSize);
|
|
} else {
|
|
two = FALSE;
|
|
whichMember = 0;
|
|
off = rowBegin*firstSize + rowOffsetBegin;
|
|
len = (ULONG) (rowOffsetEnd - rowOffsetBegin);
|
|
}
|
|
} else {
|
|
two = FALSE;
|
|
whichMember = 1;
|
|
off = rowBegin*(rowSize - firstSize) + rowOffsetBegin -
|
|
firstSize;
|
|
len = (ULONG) (rowOffsetEnd - rowOffsetBegin);
|
|
}
|
|
} else {
|
|
if (rowOffsetBegin < firstSize) {
|
|
two = TRUE;
|
|
whichMember = 0;
|
|
off = rowBegin*firstSize + rowOffsetBegin;
|
|
len = (ULONG) (firstSize - rowOffsetBegin);
|
|
off2 = rowBegin*(rowSize - firstSize);
|
|
len2 = (ULONG) (rowSize - firstSize);
|
|
} else {
|
|
two = FALSE;
|
|
whichMember = 1;
|
|
off = rowBegin*(rowSize - firstSize) + rowOffsetBegin -
|
|
firstSize;
|
|
len = (ULONG) (rowSize - rowOffsetBegin);
|
|
}
|
|
}
|
|
} else if (i == numRows - 1) {
|
|
if (!rowOffsetEnd) {
|
|
continue;
|
|
}
|
|
if (rowOffsetEnd > firstSize) {
|
|
two = TRUE;
|
|
whichMember = 0;
|
|
off = rowEnd*firstSize;
|
|
len = (ULONG) firstSize;
|
|
off2 = rowEnd*(rowSize - firstSize);
|
|
len2 = (ULONG) (rowOffsetEnd - firstSize);
|
|
} else {
|
|
two = FALSE;
|
|
whichMember = 0;
|
|
off = rowEnd*firstSize;
|
|
len = (ULONG) rowOffsetEnd;
|
|
}
|
|
} else {
|
|
two = TRUE;
|
|
whichMember = 0;
|
|
len = (ULONG) firstSize;
|
|
len2 = (ULONG) (rowSize - firstSize);
|
|
off = (rowBegin + i)*len;
|
|
off2 = (rowBegin + i)*len2;
|
|
}
|
|
|
|
p = new REDISTRIBUTION_TP;
|
|
if (!p) {
|
|
break;
|
|
}
|
|
if (!two && numRows == 1) {
|
|
p->Mdl = TransferPacket->Mdl;
|
|
} else {
|
|
if (TransferPacket->Mdl) {
|
|
if (p->AllocateMdl(vp, len)) {
|
|
IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl, vp, len);
|
|
} else {
|
|
delete p;
|
|
break;
|
|
}
|
|
vp += len;
|
|
} else {
|
|
p->Mdl = TransferPacket->Mdl;
|
|
}
|
|
}
|
|
|
|
p->Length = len;
|
|
p->Offset = off;
|
|
p->CompletionRoutine = RedistributionTransferCompletionRoutine;
|
|
p->TargetVolume = GetMemberUnprotected(whichMember);
|
|
p->Thread = TransferPacket->Thread;
|
|
p->IrpFlags = TransferPacket->IrpFlags;
|
|
p->ReadPacket = TransferPacket->ReadPacket;
|
|
p->SpecialRead = TransferPacket->SpecialRead;
|
|
p->MasterPacket = TransferPacket;
|
|
p->Redistribution = this;
|
|
p->WhichMember = whichMember;
|
|
|
|
InsertTailList(&q, &p->QueueEntry);
|
|
numRequests++;
|
|
|
|
if (!two) {
|
|
continue;
|
|
}
|
|
|
|
p = new REDISTRIBUTION_TP;
|
|
if (!p) {
|
|
break;
|
|
}
|
|
if (TransferPacket->Mdl) {
|
|
if (p->AllocateMdl(vp, len2)) {
|
|
IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl, vp, len2);
|
|
} else {
|
|
delete p;
|
|
break;
|
|
}
|
|
vp += len2;
|
|
} else {
|
|
p->Mdl = TransferPacket->Mdl;
|
|
}
|
|
|
|
p->Length = len2;
|
|
p->Offset = off2;
|
|
p->CompletionRoutine = RedistributionTransferCompletionRoutine;
|
|
p->TargetVolume = GetMemberUnprotected(1);
|
|
p->Thread = TransferPacket->Thread;
|
|
p->IrpFlags = TransferPacket->IrpFlags;
|
|
p->ReadPacket = TransferPacket->ReadPacket;
|
|
p->SpecialRead = TransferPacket->SpecialRead;
|
|
p->MasterPacket = TransferPacket;
|
|
p->Redistribution = this;
|
|
p->WhichMember = 1;
|
|
|
|
InsertTailList(&q, &p->QueueEntry);
|
|
numRequests++;
|
|
}
|
|
|
|
if (i < numRows) {
|
|
while (!IsListEmpty(&q)) {
|
|
l = RemoveHeadList(&q);
|
|
p = CONTAINING_RECORD(l, REDISTRIBUTION_TP, QueueEntry);
|
|
delete p;
|
|
}
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
KeInitializeSpinLock(&TransferPacket->SpinLock);
|
|
TransferPacket->IoStatus.Status = STATUS_SUCCESS;
|
|
TransferPacket->IoStatus.Information = TransferPacket->Length;
|
|
TransferPacket->RefCount = numRequests;
|
|
|
|
while (!IsListEmpty(&q)) {
|
|
l = RemoveHeadList(&q);
|
|
p = CONTAINING_RECORD(l, REDISTRIBUTION_TP, QueueEntry);
|
|
TRANSFER(p);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
RedistributeReplaceBadSectorCompletion(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for REDISTRIBUTION::RedistributionReplaceBadSector.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP transferPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
|
|
|
|
masterPacket->IoStatus = transferPacket->IoStatus;
|
|
delete transferPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::RedistributeReplaceBadSector(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine launches the given transfer packet using the new
|
|
redistributed data allocation scheme.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet to launch.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONGLONG begin, rowSize, rowBegin, rowOffsetBegin, firstSize, offset;
|
|
USHORT whichMember;
|
|
PREDISTRIBUTION_TP p;
|
|
|
|
begin = TransferPacket->Offset;
|
|
rowSize = _totalWidth*_stripeSize;
|
|
rowBegin = begin/rowSize;
|
|
rowOffsetBegin = begin%rowSize;
|
|
firstSize = _firstWidth*_stripeSize;
|
|
|
|
if (rowOffsetBegin < firstSize) {
|
|
offset = rowBegin*firstSize + rowOffsetBegin;
|
|
whichMember = 0;
|
|
} else {
|
|
offset = rowBegin*(rowSize - firstSize) + rowOffsetBegin - firstSize;
|
|
whichMember = 1;
|
|
}
|
|
|
|
p = new REDISTRIBUTION_TP;
|
|
if (!p) {
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
p->Mdl = TransferPacket->Mdl;
|
|
p->Length = TransferPacket->Length;
|
|
p->Offset = offset;
|
|
p->CompletionRoutine = RedistributeReplaceBadSectorCompletion;
|
|
p->TargetVolume = GetMemberUnprotected(whichMember);
|
|
p->Thread = TransferPacket->Thread;
|
|
p->IrpFlags = TransferPacket->IrpFlags;
|
|
p->ReadPacket = TransferPacket->ReadPacket;
|
|
p->SpecialRead = TransferPacket->SpecialRead;
|
|
p->MasterPacket = TransferPacket;
|
|
p->Redistribution = this;
|
|
p->WhichMember = whichMember;
|
|
|
|
p->TargetVolume->ReplaceBadSector(p);
|
|
}
|
|
|
|
VOID
|
|
RedistributionPropogateStateChangesWorker(
|
|
IN PVOID WorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a worker thread routine for propogating state changes.
|
|
|
|
Arguments:
|
|
|
|
Mirror - Supplies a pointer to the mirror object.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPROPOGATE_CHANGES_WORK_ITEM workItem = (PPROPOGATE_CHANGES_WORK_ITEM) WorkItem;
|
|
PREDISTRIBUTION t = workItem->Redistribution;
|
|
NTSTATUS status;
|
|
KIRQL irql;
|
|
FT_REDISTRIBUTION_STATE_INFORMATION state;
|
|
|
|
status = FtpAcquireWithTimeout(t->_rootExtension);
|
|
if (!NT_SUCCESS(status)) {
|
|
if (workItem->CompletionRoutine) {
|
|
workItem->CompletionRoutine(workItem->Context, status);
|
|
}
|
|
return;
|
|
}
|
|
|
|
KeAcquireSpinLock(&t->_spinLock, &irql);
|
|
RtlCopyMemory(&state, &t->_state, sizeof(state));
|
|
KeReleaseSpinLock(&t->_spinLock, irql);
|
|
|
|
status = t->_diskInfoSet->WriteStateInformation(t->QueryLogicalDiskId(),
|
|
&state, sizeof(state));
|
|
|
|
FtpRelease(t->_rootExtension);
|
|
|
|
if (workItem->CompletionRoutine) {
|
|
workItem->CompletionRoutine(workItem->Context, status);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::PropogateStateChanges(
|
|
IN FT_COMPLETION_ROUTINE CompletionRoutine,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine propogates the changes in the local memory state to
|
|
the on disk state.
|
|
|
|
Arguments:
|
|
|
|
CompletionRoutine - Supplies the completion routine.
|
|
|
|
Context - Supplies the context.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPROPOGATE_CHANGES_WORK_ITEM workItem;
|
|
|
|
workItem = (PPROPOGATE_CHANGES_WORK_ITEM)
|
|
ExAllocatePool(NonPagedPool,
|
|
sizeof(PROPOGATE_CHANGES_WORK_ITEM));
|
|
if (!workItem) {
|
|
return;
|
|
}
|
|
workItem->Redistribution = this;
|
|
workItem->CompletionRoutine = CompletionRoutine;
|
|
workItem->Context = Context;
|
|
|
|
ExInitializeWorkItem(workItem, RedistributionPropogateStateChangesWorker,
|
|
workItem);
|
|
|
|
FtpQueueWorkItem(_rootExtension, workItem);
|
|
}
|
|
|
|
VOID
|
|
RedistributionMaxTransferCompletionRoutine(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a sector transfer subordinate
|
|
to a MAX transfer operation.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the subordinate transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP subPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PREDISTRIBUTION_TP masterPacket = (PREDISTRIBUTION_TP) subPacket->MasterPacket;
|
|
NTSTATUS status = subPacket->IoStatus.Status;
|
|
|
|
if (FsRtlIsTotalDeviceFailure(status)) {
|
|
masterPacket->IoStatus = subPacket->IoStatus;
|
|
delete subPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
if (subPacket->Offset + subPacket->Length ==
|
|
masterPacket->Offset + masterPacket->Length) {
|
|
|
|
delete subPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Offset += subPacket->Length;
|
|
MmPrepareMdlForReuse(subPacket->Mdl);
|
|
IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
|
|
(PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
|
|
(ULONG) (subPacket->Offset - masterPacket->Offset),
|
|
subPacket->Length);
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::MaxTransfer(
|
|
IN OUT PREDISTRIBUTION_TP TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine propogates sector by sector the given transfer packet,
|
|
ignoring errors.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP subPacket;
|
|
|
|
TransferPacket->IoStatus.Status = STATUS_SUCCESS;
|
|
TransferPacket->IoStatus.Information = TransferPacket->Length;
|
|
|
|
subPacket = new REDISTRIBUTION_TP;
|
|
if (!subPacket) {
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Length = QuerySectorSize();
|
|
subPacket->Offset = TransferPacket->Offset;
|
|
subPacket->CompletionRoutine = RedistributionMaxTransferCompletionRoutine;
|
|
subPacket->TargetVolume = TransferPacket->TargetVolume;
|
|
subPacket->Thread = TransferPacket->Thread;
|
|
subPacket->IrpFlags = TransferPacket->IrpFlags;
|
|
subPacket->ReadPacket = TransferPacket->ReadPacket;
|
|
subPacket->MasterPacket = TransferPacket;
|
|
subPacket->Redistribution = this;
|
|
subPacket->WhichMember = TransferPacket->WhichMember;
|
|
|
|
if (!subPacket->AllocateMdl((PVOID) (PAGE_SIZE - 1), subPacket->Length)) {
|
|
delete subPacket;
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
IoBuildPartialMdl(TransferPacket->Mdl, subPacket->Mdl,
|
|
MmGetMdlVirtualAddress(TransferPacket->Mdl),
|
|
subPacket->Length);
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionVerifyWriteCompletion(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a verify write operation.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the subordinate transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP verifyPacket = (PREDISTRIBUTION_TP) TransferPacket;
|
|
PREDISTRIBUTION_TP masterPacket = (PREDISTRIBUTION_TP) verifyPacket->MasterPacket;
|
|
NTSTATUS status = verifyPacket->IoStatus.Status;
|
|
PVOID p, q;
|
|
ULONG l;
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
masterPacket->IoStatus = verifyPacket->IoStatus;
|
|
delete verifyPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
p = MmGetSystemAddressForMdl(verifyPacket->Mdl);
|
|
q = MmGetSystemAddressForMdl(masterPacket->Mdl);
|
|
l = (ULONG)RtlCompareMemory(p, q, verifyPacket->Length);
|
|
if (l != verifyPacket->Length) {
|
|
masterPacket->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
|
|
masterPacket->IoStatus.Information = 0;
|
|
}
|
|
|
|
delete verifyPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::VerifyWrite(
|
|
IN OUT PREDISTRIBUTION_TP TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine verifies that the given write was success by reading
|
|
and comparing.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_TP verifyPacket;
|
|
|
|
verifyPacket = new REDISTRIBUTION_TP;
|
|
if (!verifyPacket) {
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
if (!verifyPacket->AllocateMdl(TransferPacket->Length)) {
|
|
delete verifyPacket;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
verifyPacket->Length = TransferPacket->Length;
|
|
verifyPacket->Offset = TransferPacket->Offset;
|
|
verifyPacket->CompletionRoutine = RedistributionVerifyWriteCompletion;
|
|
verifyPacket->TargetVolume = TransferPacket->TargetVolume;
|
|
verifyPacket->Thread = TransferPacket->Thread;
|
|
verifyPacket->IrpFlags = TransferPacket->IrpFlags;
|
|
verifyPacket->ReadPacket = TRUE;
|
|
verifyPacket->MasterPacket = TransferPacket;
|
|
verifyPacket->Redistribution = this;
|
|
verifyPacket->WhichMember = TransferPacket->WhichMember;
|
|
|
|
TRANSFER(verifyPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionCarefulWritePhase1(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
);
|
|
|
|
VOID
|
|
RedistributionCarefulWritePhase5(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a sector read subordinate
|
|
to a carefule write operation after a replace bad sector.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the subordinate transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_CW_TP subPacket = (PREDISTRIBUTION_CW_TP) TransferPacket;
|
|
PREDISTRIBUTION_TP masterPacket = (PREDISTRIBUTION_TP) subPacket->MasterPacket;
|
|
NTSTATUS status = subPacket->IoStatus.Status;
|
|
PVOID p, q;
|
|
ULONG l;
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
p = MmGetSystemAddressForMdl(subPacket->PartialMdl);
|
|
q = MmGetSystemAddressForMdl(subPacket->VerifyMdl);
|
|
l = (ULONG)RtlCompareMemory(p, q, subPacket->Length);
|
|
} else {
|
|
l = 0;
|
|
}
|
|
|
|
if (l != subPacket->Length) {
|
|
masterPacket->IoStatus = subPacket->IoStatus;
|
|
delete subPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
if (subPacket->Offset + subPacket->Length ==
|
|
masterPacket->Offset + masterPacket->Length) {
|
|
|
|
delete subPacket;
|
|
masterPacket->IoStatus.Status = STATUS_SUCCESS;
|
|
masterPacket->IoStatus.Information = masterPacket->Length;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Offset += subPacket->Length;
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase1;
|
|
subPacket->ReadPacket = FALSE;
|
|
|
|
subPacket->Mdl = subPacket->PartialMdl;
|
|
MmPrepareMdlForReuse(subPacket->Mdl);
|
|
IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
|
|
(PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
|
|
(ULONG) (subPacket->Offset - masterPacket->Offset),
|
|
subPacket->Length);
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionCarefulWritePhase4(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a sector write subordinate
|
|
to a carefule write operation after a sector replace operation.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the subordinate transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_CW_TP subPacket = (PREDISTRIBUTION_CW_TP) TransferPacket;
|
|
PREDISTRIBUTION_TP masterPacket = (PREDISTRIBUTION_TP) subPacket->MasterPacket;
|
|
NTSTATUS status = subPacket->IoStatus.Status;
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
masterPacket->IoStatus = subPacket->IoStatus;
|
|
delete subPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Mdl = subPacket->VerifyMdl;
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase5;
|
|
subPacket->ReadPacket = TRUE;
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionCarefulWritePhase3(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a sector replace subordinate
|
|
to a carefule write operation.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the subordinate transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_CW_TP subPacket = (PREDISTRIBUTION_CW_TP) TransferPacket;
|
|
PREDISTRIBUTION_TP masterPacket = (PREDISTRIBUTION_TP) subPacket->MasterPacket;
|
|
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase4;
|
|
subPacket->ReadPacket = FALSE;
|
|
|
|
subPacket->Mdl = subPacket->PartialMdl;
|
|
MmPrepareMdlForReuse(subPacket->Mdl);
|
|
IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
|
|
(PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
|
|
(ULONG) (subPacket->Offset - masterPacket->Offset),
|
|
subPacket->Length);
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionCarefulWritePhase2(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a sector read subordinate
|
|
to a carefule write operation.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the subordinate transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_CW_TP subPacket = (PREDISTRIBUTION_CW_TP) TransferPacket;
|
|
PREDISTRIBUTION_TP masterPacket = (PREDISTRIBUTION_TP) subPacket->MasterPacket;
|
|
NTSTATUS status = subPacket->IoStatus.Status;
|
|
PVOID p, q;
|
|
ULONG l;
|
|
|
|
if (FsRtlIsTotalDeviceFailure(status)) {
|
|
masterPacket->IoStatus = subPacket->IoStatus;
|
|
delete subPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
p = MmGetSystemAddressForMdl(subPacket->PartialMdl);
|
|
q = MmGetSystemAddressForMdl(subPacket->VerifyMdl);
|
|
l = (ULONG)RtlCompareMemory(p, q, subPacket->Length);
|
|
} else {
|
|
l = 0;
|
|
}
|
|
|
|
if (l != subPacket->Length) {
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase3;
|
|
subPacket->TargetVolume->ReplaceBadSector(subPacket);
|
|
return;
|
|
}
|
|
|
|
if (subPacket->Offset + subPacket->Length ==
|
|
masterPacket->Offset + masterPacket->Length) {
|
|
|
|
delete subPacket;
|
|
masterPacket->IoStatus.Status = STATUS_SUCCESS;
|
|
masterPacket->IoStatus.Information = masterPacket->Length;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Offset += subPacket->Length;
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase1;
|
|
subPacket->ReadPacket = FALSE;
|
|
|
|
subPacket->Mdl = subPacket->PartialMdl;
|
|
MmPrepareMdlForReuse(subPacket->Mdl);
|
|
IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
|
|
(PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
|
|
(ULONG) (subPacket->Offset - masterPacket->Offset),
|
|
subPacket->Length);
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
VOID
|
|
RedistributionCarefulWritePhase1(
|
|
IN OUT PTRANSFER_PACKET TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the completion routine for a sector write subordinate
|
|
to a carefule write operation.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the subordinate transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_CW_TP subPacket = (PREDISTRIBUTION_CW_TP) TransferPacket;
|
|
PREDISTRIBUTION_TP masterPacket = (PREDISTRIBUTION_TP) subPacket->MasterPacket;
|
|
NTSTATUS status = subPacket->IoStatus.Status;
|
|
|
|
if (FsRtlIsTotalDeviceFailure(status)) {
|
|
masterPacket->IoStatus = subPacket->IoStatus;
|
|
delete subPacket;
|
|
masterPacket->CompletionRoutine(masterPacket);
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase3;
|
|
subPacket->TargetVolume->ReplaceBadSector(subPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Mdl = subPacket->VerifyMdl;
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase2;
|
|
subPacket->ReadPacket = TRUE;
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
VOID
|
|
REDISTRIBUTION::CarefulWrite(
|
|
IN OUT PREDISTRIBUTION_TP TransferPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes the given packet, sector by sector, replacing
|
|
bad sectors if need be.
|
|
|
|
Arguments:
|
|
|
|
TransferPacket - Supplies the transfer packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDISTRIBUTION_CW_TP subPacket;
|
|
|
|
ASSERT(!TransferPacket->ReadPacket);
|
|
|
|
subPacket = new REDISTRIBUTION_CW_TP;
|
|
if (!subPacket) {
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Length = QuerySectorSize();
|
|
subPacket->Offset = TransferPacket->Offset;
|
|
subPacket->CompletionRoutine = RedistributionCarefulWritePhase1;
|
|
subPacket->TargetVolume = TransferPacket->TargetVolume;
|
|
subPacket->Thread = TransferPacket->Thread;
|
|
subPacket->IrpFlags = TransferPacket->IrpFlags;
|
|
subPacket->ReadPacket = FALSE;
|
|
subPacket->MasterPacket = TransferPacket;
|
|
subPacket->Redistribution = TransferPacket->Redistribution;
|
|
subPacket->WhichMember = TransferPacket->WhichMember;
|
|
|
|
if (!subPacket->AllocateMdls(subPacket->Length)) {
|
|
delete subPacket;
|
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TransferPacket->IoStatus.Information = 0;
|
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|
return;
|
|
}
|
|
|
|
subPacket->Mdl = subPacket->PartialMdl;
|
|
IoBuildPartialMdl(TransferPacket->Mdl, subPacket->Mdl,
|
|
MmGetMdlVirtualAddress(TransferPacket->Mdl),
|
|
subPacket->Length);
|
|
|
|
TRANSFER(subPacket);
|
|
}
|
|
|
|
NTSTATUS
|
|
REDISTRIBUTION::QueryPhysicalOffsets(
|
|
IN LONGLONG LogicalOffset,
|
|
OUT PVOLUME_PHYSICAL_OFFSET* PhysicalOffsets,
|
|
OUT PULONG NumberOfPhysicalOffsets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns physical disk and offset for a given volume
|
|
logical offset.
|
|
|
|
Arguments:
|
|
|
|
LogicalOffset - Supplies the logical offset
|
|
|
|
PhysicalOffsets - Returns the physical offsets
|
|
|
|
NumberOfPhysicalOffsets - Returns the number of physical offsets
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
USHORT n, whichMember, whichStripeInSet;
|
|
LONGLONG whichStripe, whichSet, whichRow;
|
|
LONGLONG bytesRedistributed, logicalOffsetInMember;
|
|
PFT_VOLUME vol;
|
|
KIRQL irql;
|
|
|
|
if (LogicalOffset < 0) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (_redistributionComplete) {
|
|
if (_totalSize <= LogicalOffset) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|
bytesRedistributed = _state.BytesRedistributed;
|
|
KeReleaseSpinLock(&_spinLock, irql);
|
|
if (bytesRedistributed <= LogicalOffset) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
ASSERT(_stripeSize);
|
|
ASSERT(_totalWidth);
|
|
|
|
whichStripe = LogicalOffset/_stripeSize;
|
|
whichSet = whichStripe/_totalWidth;
|
|
whichStripeInSet = (USHORT) (whichStripe%_totalWidth);
|
|
if (whichStripeInSet < _firstWidth) {
|
|
whichMember = 0;
|
|
whichRow = whichSet*_firstWidth + whichStripeInSet;
|
|
} else {
|
|
whichMember = 1;
|
|
whichRow = whichSet*(_totalWidth-_firstWidth) + whichStripeInSet - _firstWidth;
|
|
}
|
|
|
|
vol = GetMember(whichMember);
|
|
if (!vol) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
logicalOffsetInMember = whichRow*_stripeSize + LogicalOffset%_stripeSize;
|
|
|
|
return vol->QueryPhysicalOffsets(logicalOffsetInMember, PhysicalOffsets, NumberOfPhysicalOffsets);
|
|
}
|
|
|
|
NTSTATUS
|
|
REDISTRIBUTION::QueryLogicalOffset(
|
|
IN PVOLUME_PHYSICAL_OFFSET PhysicalOffset,
|
|
OUT PLONGLONG LogicalOffset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the volume logical offset for a given disk number
|
|
and physical offset.
|
|
|
|
Arguments:
|
|
|
|
PhysicalOffset - Supplies the physical offset
|
|
|
|
LogicalOffset - Returns the logical offset
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
USHORT n, i, whichStripeInSet;
|
|
LONGLONG whichStripe, whichSet, whichRow, bytesRedistributed;
|
|
LONGLONG logicalOffset, logicalOffsetInMember;
|
|
NTSTATUS status;
|
|
PFT_VOLUME vol;
|
|
KIRQL irql;
|
|
|
|
n = QueryNumMembers();
|
|
|
|
ASSERT(n == 2);
|
|
ASSERT(_stripeSize);
|
|
ASSERT(_firstWidth);
|
|
ASSERT(_totalWidth > _firstWidth);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
vol = GetMember(i);
|
|
if (!vol) {
|
|
continue;
|
|
}
|
|
status = vol->QueryLogicalOffset(PhysicalOffset, &logicalOffsetInMember);
|
|
if (NT_SUCCESS(status)) {
|
|
whichRow = logicalOffsetInMember/_stripeSize;
|
|
if (i == 0) {
|
|
whichSet = whichRow/_firstWidth;
|
|
whichStripeInSet = (USHORT) (whichRow%_firstWidth);
|
|
} else {
|
|
ASSERT(i == 1);
|
|
whichSet = whichRow/(_totalWidth-_firstWidth);
|
|
whichStripeInSet = (USHORT) (whichRow%(_totalWidth-_firstWidth)) + _firstWidth;
|
|
}
|
|
whichStripe = whichSet*_totalWidth + whichStripeInSet;
|
|
logicalOffset = whichStripe*_stripeSize + logicalOffsetInMember%_stripeSize;
|
|
|
|
if (_redistributionComplete) {
|
|
if (_totalSize <= logicalOffset) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|
bytesRedistributed = _state.BytesRedistributed;
|
|
KeReleaseSpinLock(&_spinLock, irql);
|
|
if (bytesRedistributed <= logicalOffset) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
*LogicalOffset = logicalOffset;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|