NT4/private/ntos/dd/newft/stripe.cxx
2020-09-30 17:12:29 +02:00

718 lines
16 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991-5 Microsoft Corporation
Module Name:
stripe.cxx
Abstract:
This module contains the code specific to volume sets for the fault
tolerance driver.
Author:
Bob Rinne (bobri) 2-Feb-1992
Mike Glass (mglass)
Norbert Kusters 2-Feb-1995
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include "ftdisk.h"
STRIPE::~STRIPE(
)
{
if (_ePacket) {
delete _ePacket;
_ePacket = NULL;
}
}
NTSTATUS
STRIPE::Initialize(
IN OUT PFT_VOLUME* VolumeArray,
IN ULONG ArraySize
)
/*++
Routine Description:
Initialize routine for FT_VOLUME of type STRIPE.
Arguments:
VolumeArray - Supplies the array of volumes for this volume set.
Return Value:
None.
--*/
{
NTSTATUS status;
ULONG i;
LONGLONG newSize;
status = COMPOSITE_FT_VOLUME::Initialize(VolumeArray, ArraySize);
if (!NT_SUCCESS(status)) {
return status;
}
_memberSize = VolumeArray[0]->QueryVolumeSize();
for (i = 1; i < ArraySize; i++) {
newSize = VolumeArray[i]->QueryVolumeSize();
if (_memberSize > newSize) {
_memberSize = newSize;
}
}
_memberSize = _memberSize/_stripeSize*_stripeSize;
_volumeSize = _memberSize*ArraySize;
_ePacket = new STRIPE_TP;
if (_ePacket && !_ePacket->AllocateMdl((PVOID) 1, _stripeSize)) {
delete _ePacket;
_ePacket = NULL;
}
if (!_ePacket) {
return STATUS_INSUFFICIENT_RESOURCES;
}
_ePacketInUse = FALSE;
InitializeListHead(&_ePacketQueue);
return status;
}
VOID
StripeReplaceCompletionRoutine(
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.
--*/
{
PSTRIPE_TP transferPacket = (PSTRIPE_TP) TransferPacket;
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
masterPacket->IoStatus = transferPacket->IoStatus;
delete transferPacket;
masterPacket->CompletionRoutine(masterPacket);
}
VOID
STRIPE::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.
--*/
{
ULONG n, whichMember;
LONGLONG whichStripe, whichRow;
PSTRIPE_TP p;
n = QueryNumMembers();
whichStripe = TransferPacket->Offset/_stripeSize;
whichMember = (ULONG) (whichStripe%n);
whichRow = whichStripe/n;
p = new STRIPE_TP;
if (!p) {
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
p->Length = TransferPacket->Length;
p->Offset = whichRow*_stripeSize + TransferPacket->Offset%_stripeSize;
p->CompletionRoutine = StripeReplaceCompletionRoutine;
p->TargetVolume = GetMemberUnprotected(whichMember);
p->Thread = TransferPacket->Thread;
p->IrpFlags = TransferPacket->IrpFlags;
p->MasterPacket = TransferPacket;
p->Stripe = this;
p->WhichMember = whichMember;
p->TargetVolume->ReplaceBadSector(p);
}
VOID
STRIPE::Transfer(
IN OUT PTRANSFER_PACKET TransferPacket
)
/*++
Routine Description:
Transfer routine for STRIPE type FT_VOLUME. Figure out
which volumes this request needs to be dispatched to.
Arguments:
TransferPacket - Supplies the transfer packet.
Return Value:
None.
--*/
{
KIRQL irql;
if (TransferPacket->Offset + TransferPacket->Length > _volumeSize) {
TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
KeAcquireSpinLock(&_spinLock, &irql);
if (_ePacketInUse && TransferPacket->Mdl) {
InsertTailList(&_ePacketQueue, &TransferPacket->QueueEntry);
KeReleaseSpinLock(&_spinLock, irql);
return;
}
KeReleaseSpinLock(&_spinLock, irql);
if (!LaunchParallel(TransferPacket)) {
if (!TransferPacket->Mdl) {
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
KeAcquireSpinLock(&_spinLock, &irql);
if (_ePacketInUse) {
InsertTailList(&_ePacketQueue, &TransferPacket->QueueEntry);
KeReleaseSpinLock(&_spinLock, irql);
return;
}
_ePacketInUse = TRUE;
KeReleaseSpinLock(&_spinLock, irql);
LaunchSequential(TransferPacket);
}
}
BOOLEAN
STRIPE::IsCreatingCheckData(
)
/*++
Routine Description:
This routine states whether or not this VOLUME is currently creating
check data. The state refers to this volume and does not reflect the
state of volumes contained within this volume.
Arguments:
None.
Return Value:
FALSE - This volume is not creating check data (although a child volume
may be).
TRUE - This volume is creating check data.
--*/
{
return FALSE;
}
VOID
STRIPE::SetCheckDataDirty(
)
/*++
Routine Description:
This routine marks the check data as dirty so that when
'StartSyncOperations' is called, the check data will be
initialized.
Arguments:
None.
Return Value:
None.
--*/
{
}
LONGLONG
STRIPE::QueryVolumeSize(
)
/*++
Routine Description:
Returns the number of bytes on the entire volume.
Arguments:
None.
Return Value:
The volume size in bytes.
--*/
{
return _volumeSize;
}
FT_TYPE
STRIPE::QueryVolumeType(
)
/*++
Routine Description:
Returns the volume type.
Arguments:
None.
Return Value:
Stripe - A stripe set.
--*/
{
return Stripe;
}
FT_STATE
STRIPE::QueryVolumeState(
)
/*++
Routine Description:
Returns the state of the volume.
Arguments:
None.
Return Value:
FtStateOk - The volume is fine.
--*/
{
return FtStateOk;
}
VOID
StripeTransferParallelCompletionRoutine(
IN PTRANSFER_PACKET TransferPacket
)
/*++
Routine Description:
Completion routine for STRIPE::Transfer function.
Arguments:
TransferPacket - Supplies the transfer packet.
Return Value:
None.
--*/
{
PSTRIPE_TP transferPacket = (PSTRIPE_TP) TransferPacket;
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
NTSTATUS status = transferPacket->IoStatus.Status;
KIRQL irql;
LONG count;
KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
if (NT_SUCCESS(status)) {
if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
masterPacket->IoStatus.Information +=
transferPacket->IoStatus.Information;
}
} else {
if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
masterPacket->IoStatus.Status = status;
}
}
count = --masterPacket->RefCount;
KeReleaseSpinLock(&masterPacket->SpinLock, irql);
delete transferPacket;
if (!count) {
masterPacket->CompletionRoutine(masterPacket);
}
}
BOOLEAN
STRIPE::LaunchParallel(
IN OUT PTRANSFER_PACKET TransferPacket
)
/*++
Routine Description:
This routine lauches the given transfer packet in parallel accross
all members. If memory cannot be allocated to launch this request
in parallel then a return value of FALSE will be returned.
Arguments:
TransferPacket - Supplies the transfer packet to launch.
Return Value:
FALSE - The packet was not launched because of insufficient resources.
TRUE - Success.
--*/
{
LONGLONG offset, whichStripe, whichRow, off;
ULONG length, stripeRemainder, numRequests, arraySize, whichMember, len;
PSTRIPE_TP p;
ULONG i;
PCHAR vp;
LIST_ENTRY q;
PLIST_ENTRY l;
// Compute the number of pieces for this transfer.
offset = TransferPacket->Offset;
length = TransferPacket->Length;
stripeRemainder = _stripeSize - (ULONG) (offset%_stripeSize);
if (length > stripeRemainder) {
length -= stripeRemainder;
numRequests = length/_stripeSize;
length -= numRequests*_stripeSize;
if (length) {
numRequests += 2;
} else {
numRequests++;
}
} else {
numRequests = 1;
}
KeInitializeSpinLock(&TransferPacket->SpinLock);
TransferPacket->IoStatus.Status = STATUS_SUCCESS;
TransferPacket->IoStatus.Information = 0;
TransferPacket->RefCount = numRequests;
length = TransferPacket->Length;
if (TransferPacket->Mdl && numRequests > 1) {
vp = (PCHAR) MmGetMdlVirtualAddress(TransferPacket->Mdl);
}
whichStripe = offset/_stripeSize;
arraySize = QueryNumMembers();
InitializeListHead(&q);
for (i = 0; i < numRequests; i++, whichStripe++) {
whichRow = whichStripe/arraySize;
whichMember = (ULONG) (whichStripe%arraySize);
if (i == 0) {
off = whichRow*_stripeSize + offset%_stripeSize;
len = stripeRemainder > length ? length : stripeRemainder;
} else if (i == numRequests - 1) {
off = whichRow*_stripeSize;
len = length;
} else {
off = whichRow*_stripeSize;
len = _stripeSize;
}
length -= len;
p = new STRIPE_TP;
if (p) {
if (TransferPacket->Mdl && numRequests > 1) {
if (p->AllocateMdl(vp, len)) {
IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl, vp, len);
} else {
delete p;
p = NULL;
}
vp += len;
} else {
p->Mdl = TransferPacket->Mdl;
}
}
if (!p) {
while (!IsListEmpty(&q)) {
l = RemoveHeadList(&q);
p = CONTAINING_RECORD(l, STRIPE_TP, QueueEntry);
delete p;
}
return FALSE;
}
p->Length = len;
p->Offset = off;
p->CompletionRoutine = StripeTransferParallelCompletionRoutine;
p->TargetVolume = GetMemberUnprotected(whichMember);
p->Thread = TransferPacket->Thread;
p->IrpFlags = TransferPacket->IrpFlags;
p->ReadPacket = TransferPacket->ReadPacket;
p->MasterPacket = TransferPacket;
p->Stripe = this;
p->WhichMember = whichMember;
InsertTailList(&q, &p->QueueEntry);
}
while (!IsListEmpty(&q)) {
l = RemoveHeadList(&q);
p = CONTAINING_RECORD(l, STRIPE_TP, QueueEntry);
TRANSFER(p);
}
return TRUE;
}
VOID
StripeSequentialTransferCompletionRoutine(
IN PTRANSFER_PACKET TransferPacket
)
/*++
Routine Description:
Completion routine for STRIPE::Transfer function.
Arguments:
TransferPacket - Supplies the transfer packet.
Return Value:
None.
--*/
{
PSTRIPE_TP transferPacket = (PSTRIPE_TP) TransferPacket;
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
NTSTATUS status = transferPacket->IoStatus.Status;
PSTRIPE t = transferPacket->Stripe;
LONGLONG rowNumber, stripeNumber, masterOffset;
KIRQL irql;
PLIST_ENTRY l;
PTRANSFER_PACKET p;
if (NT_SUCCESS(status)) {
if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
masterPacket->IoStatus.Information +=
transferPacket->IoStatus.Information;
}
} else {
if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
masterPacket->IoStatus.Status = status;
masterPacket->IoStatus.Information = 0;
}
}
MmPrepareMdlForReuse(transferPacket->Mdl);
rowNumber = transferPacket->Offset/t->_stripeSize;
stripeNumber = rowNumber*t->QueryNumMembers() +
transferPacket->WhichMember;
masterOffset = stripeNumber*t->_stripeSize +
transferPacket->Offset%t->_stripeSize;
if (masterOffset + transferPacket->Length ==
masterPacket->Offset + masterPacket->Length) {
masterPacket->CompletionRoutine(masterPacket);
for (;;) {
KeAcquireSpinLock(&t->_spinLock, &irql);
if (IsListEmpty(&t->_ePacketQueue)) {
t->_ePacketInUse = FALSE;
KeReleaseSpinLock(&t->_spinLock, irql);
break;
}
l = RemoveHeadList(&t->_ePacketQueue);
KeReleaseSpinLock(&t->_spinLock, irql);
p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
if (!t->LaunchParallel(p)) {
t->LaunchSequential(p);
break;
}
}
return;
}
transferPacket->WhichMember++;
if (transferPacket->WhichMember == t->QueryNumMembers()) {
transferPacket->WhichMember = 0;
rowNumber++;
}
masterOffset += transferPacket->Length;
transferPacket->Offset = rowNumber*t->_stripeSize;
transferPacket->Length = t->_stripeSize;
if (masterOffset + transferPacket->Length >
masterPacket->Offset + masterPacket->Length) {
transferPacket->Length = (ULONG) (masterPacket->Offset +
masterPacket->Length - masterOffset);
}
transferPacket->TargetVolume =
t->GetMemberUnprotected(transferPacket->WhichMember);
IoBuildPartialMdl(masterPacket->Mdl, transferPacket->Mdl,
(PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
(ULONG) (masterOffset - masterPacket->Offset),
transferPacket->Length);
TRANSFER(transferPacket);
}
VOID
STRIPE::LaunchSequential(
IN OUT PTRANSFER_PACKET TransferPacket
)
/*++
Routine Description:
This routine lauches the given transfer packet in sequence accross
all members using the emergency stripe transfer packet.
Arguments:
TransferPacket - Supplies the transfer packet to launch.
Return Value:
FALSE - The packet was not launched because of insufficient resources.
TRUE - Success.
--*/
{
PSTRIPE_TP p;
LONGLONG offset, whichStripe, whichRow;
ULONG whichMember, arraySize;
TransferPacket->IoStatus.Status = STATUS_SUCCESS;
TransferPacket->IoStatus.Information = 0;
offset = TransferPacket->Offset;
p = _ePacket;
arraySize = QueryNumMembers();
whichStripe = offset/_stripeSize;
whichRow = whichStripe/arraySize;
whichMember = (ULONG) (whichStripe%arraySize);
p->Length = _stripeSize - (ULONG) (offset%_stripeSize);
if (p->Length > TransferPacket->Length) {
p->Length = TransferPacket->Length;
}
IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl,
MmGetMdlVirtualAddress(TransferPacket->Mdl), p->Length);
p->Offset = whichRow*_stripeSize + offset%_stripeSize;
p->CompletionRoutine = StripeSequentialTransferCompletionRoutine;
p->TargetVolume = GetMemberUnprotected(whichMember);
p->Thread = TransferPacket->Thread;
p->IrpFlags = TransferPacket->IrpFlags;
p->ReadPacket = TransferPacket->ReadPacket;
p->MasterPacket = TransferPacket;
p->Stripe = this;
p->WhichMember = whichMember;
TRANSFER(p);
}