724 lines
15 KiB
C++
724 lines
15 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-5 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
volset.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"
|
|||
|
|
|||
|
|
|||
|
VOLUME_SET::~VOLUME_SET(
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
if (_ePacket) {
|
|||
|
delete _ePacket;
|
|||
|
_ePacket = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
VOLUME_SET::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;
|
|||
|
|
|||
|
status = COMPOSITE_FT_VOLUME::Initialize(VolumeArray, ArraySize);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
_volumeSize = 0;
|
|||
|
for (i = 0; i < ArraySize; i++) {
|
|||
|
_volumeSize += VolumeArray[i]->QueryVolumeSize();
|
|||
|
}
|
|||
|
|
|||
|
_ePacket = new VOLSET_TP;
|
|||
|
if (_ePacket && !_ePacket->AllocateMdl((PVOID) 1, STRIPE_SIZE)) {
|
|||
|
delete _ePacket;
|
|||
|
_ePacket = NULL;
|
|||
|
}
|
|||
|
if (!_ePacket) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
_ePacketInUse = FALSE;
|
|||
|
InitializeListHead(&_ePacketQueue);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
VOLUME_SET::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);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
VolsetReplaceCompletionRoutine(
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PVOLSET_TP transferPacket = (PVOLSET_TP) TransferPacket;
|
|||
|
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
|
|||
|
|
|||
|
masterPacket->IoStatus = transferPacket->IoStatus;
|
|||
|
delete transferPacket;
|
|||
|
masterPacket->CompletionRoutine(masterPacket);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
VOLUME_SET::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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONGLONG offset = TransferPacket->Offset;
|
|||
|
ULONG n, i;
|
|||
|
PVOLSET_TP p;
|
|||
|
LONGLONG volumeSize;
|
|||
|
|
|||
|
n = QueryNumMembers();
|
|||
|
for (i = 0; i < n; i++) {
|
|||
|
volumeSize = GetMemberUnprotected(i)->QueryVolumeSize();
|
|||
|
if (offset < volumeSize) {
|
|||
|
break;
|
|||
|
}
|
|||
|
offset -= volumeSize;
|
|||
|
}
|
|||
|
|
|||
|
p = new VOLSET_TP;
|
|||
|
if (!p) {
|
|||
|
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
TransferPacket->IoStatus.Information = 0;
|
|||
|
TransferPacket->CompletionRoutine(TransferPacket);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
p->Length = TransferPacket->Length;
|
|||
|
p->Offset = offset;
|
|||
|
p->CompletionRoutine = VolsetReplaceCompletionRoutine;
|
|||
|
p->TargetVolume = GetMemberUnprotected(i);
|
|||
|
p->Thread = TransferPacket->Thread;
|
|||
|
p->IrpFlags = TransferPacket->IrpFlags;
|
|||
|
p->MasterPacket = TransferPacket;
|
|||
|
p->VolumeSet = this;
|
|||
|
p->WhichMember = i;
|
|||
|
|
|||
|
p->TargetVolume->ReplaceBadSector(p);
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
VOLUME_SET::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
|
|||
|
VOLUME_SET::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
|
|||
|
VOLUME_SET::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
|
|||
|
VOLUME_SET::QueryVolumeType(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the volume type.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Stripe - A stripe set.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return VolumeSet;
|
|||
|
}
|
|||
|
|
|||
|
FT_STATE
|
|||
|
VOLUME_SET::QueryVolumeState(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the state of the volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FtStateOk - The volume is fine.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return FtStateOk;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
VolsetTransferParallelCompletionRoutine(
|
|||
|
IN PTRANSFER_PACKET TransferPacket
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Completion routine for VOLUME_SET::Transfer function.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TransferPacket - Supplies the transfer packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PVOLSET_TP transferPacket = (PVOLSET_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
|
|||
|
VOLUME_SET::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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG arraySize, length, i, len;
|
|||
|
LONGLONG offset, volumeSize;
|
|||
|
BOOLEAN multiple;
|
|||
|
PCHAR vp;
|
|||
|
LIST_ENTRY q;
|
|||
|
PVOLSET_TP p;
|
|||
|
PLIST_ENTRY l;
|
|||
|
|
|||
|
KeInitializeSpinLock(&TransferPacket->SpinLock);
|
|||
|
TransferPacket->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
TransferPacket->IoStatus.Information = 0;
|
|||
|
TransferPacket->RefCount = 0;
|
|||
|
|
|||
|
arraySize = QueryNumMembers();
|
|||
|
offset = TransferPacket->Offset;
|
|||
|
length = TransferPacket->Length;
|
|||
|
for (i = 0; i < arraySize; i++) {
|
|||
|
volumeSize = GetMemberUnprotected(i)->QueryVolumeSize();
|
|||
|
if (offset < volumeSize) {
|
|||
|
if (offset + length <= volumeSize) {
|
|||
|
multiple = FALSE;
|
|||
|
} else {
|
|||
|
multiple = TRUE;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
offset -= volumeSize;
|
|||
|
}
|
|||
|
|
|||
|
if (TransferPacket->Mdl && multiple) {
|
|||
|
vp = (PCHAR) MmGetMdlVirtualAddress(TransferPacket->Mdl);
|
|||
|
}
|
|||
|
|
|||
|
InitializeListHead(&q);
|
|||
|
for (;;) {
|
|||
|
|
|||
|
len = length;
|
|||
|
if (len > volumeSize - offset) {
|
|||
|
len = (ULONG) (volumeSize - offset);
|
|||
|
}
|
|||
|
|
|||
|
p = new VOLSET_TP;
|
|||
|
if (p) {
|
|||
|
if (TransferPacket->Mdl && multiple) {
|
|||
|
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, VOLSET_TP, QueueEntry);
|
|||
|
delete p;
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
p->Length = len;
|
|||
|
p->Offset = offset;
|
|||
|
p->CompletionRoutine = VolsetTransferParallelCompletionRoutine;
|
|||
|
p->TargetVolume = GetMemberUnprotected(i);
|
|||
|
p->Thread = TransferPacket->Thread;
|
|||
|
p->IrpFlags = TransferPacket->IrpFlags;
|
|||
|
p->ReadPacket = TransferPacket->ReadPacket;
|
|||
|
p->MasterPacket = TransferPacket;
|
|||
|
p->VolumeSet = this;
|
|||
|
p->WhichMember = i;
|
|||
|
|
|||
|
InsertTailList(&q, &p->QueueEntry);
|
|||
|
|
|||
|
TransferPacket->RefCount++;
|
|||
|
|
|||
|
if (len == length) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
offset = 0;
|
|||
|
length -= p->Length;
|
|||
|
volumeSize = GetMemberUnprotected(++i)->QueryVolumeSize();
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty(&q)) {
|
|||
|
l = RemoveHeadList(&q);
|
|||
|
p = CONTAINING_RECORD(l, VOLSET_TP, QueueEntry);
|
|||
|
TRANSFER(p);
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
VolsetTransferSequentialCompletionRoutine(
|
|||
|
IN PTRANSFER_PACKET TransferPacket
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Completion routine for VOLUME_SET::Transfer function.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TransferPacket - Supplies the transfer packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PVOLSET_TP transferPacket = (PVOLSET_TP) TransferPacket;
|
|||
|
PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
|
|||
|
NTSTATUS status = transferPacket->IoStatus.Status;
|
|||
|
PVOLUME_SET t = transferPacket->VolumeSet;
|
|||
|
LONGLONG masterOffset, volumeSize;
|
|||
|
ULONG i;
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MmPrepareMdlForReuse(transferPacket->Mdl);
|
|||
|
|
|||
|
masterOffset = 0;
|
|||
|
for (i = 0; i < transferPacket->WhichMember; i++) {
|
|||
|
masterOffset += t->GetMemberUnprotected(i)->QueryVolumeSize();
|
|||
|
}
|
|||
|
masterOffset += transferPacket->Offset;
|
|||
|
masterOffset += transferPacket->Length;
|
|||
|
|
|||
|
if (masterOffset == 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;
|
|||
|
}
|
|||
|
|
|||
|
volumeSize = transferPacket->TargetVolume->QueryVolumeSize();
|
|||
|
transferPacket->Offset += transferPacket->Length;
|
|||
|
transferPacket->Length = STRIPE_SIZE;
|
|||
|
|
|||
|
if (transferPacket->Offset >= volumeSize) {
|
|||
|
transferPacket->Offset -= volumeSize;
|
|||
|
transferPacket->WhichMember++;
|
|||
|
transferPacket->TargetVolume =
|
|||
|
t->GetMemberUnprotected(transferPacket->WhichMember);
|
|||
|
volumeSize = transferPacket->TargetVolume->QueryVolumeSize();
|
|||
|
}
|
|||
|
|
|||
|
if (masterOffset + transferPacket->Length >
|
|||
|
masterPacket->Offset + masterPacket->Length) {
|
|||
|
|
|||
|
transferPacket->Length = (ULONG) (masterPacket->Offset +
|
|||
|
masterPacket->Length - masterOffset);
|
|||
|
}
|
|||
|
|
|||
|
if (transferPacket->Offset + transferPacket->Length > volumeSize) {
|
|||
|
transferPacket->Length = (ULONG) (volumeSize - transferPacket->Offset);
|
|||
|
}
|
|||
|
|
|||
|
IoBuildPartialMdl(masterPacket->Mdl, transferPacket->Mdl,
|
|||
|
(PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
|
|||
|
(ULONG) (masterOffset - masterPacket->Offset),
|
|||
|
transferPacket->Length);
|
|||
|
|
|||
|
TRANSFER(transferPacket);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
VOLUME_SET::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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG arraySize, length, i;
|
|||
|
LONGLONG offset, volumeSize;
|
|||
|
PVOLSET_TP p;
|
|||
|
|
|||
|
TransferPacket->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
TransferPacket->IoStatus.Information = 0;
|
|||
|
|
|||
|
arraySize = QueryNumMembers();
|
|||
|
offset = TransferPacket->Offset;
|
|||
|
length = TransferPacket->Length;
|
|||
|
for (i = 0; i < arraySize; i++) {
|
|||
|
volumeSize = GetMemberUnprotected(i)->QueryVolumeSize();
|
|||
|
if (offset < volumeSize) {
|
|||
|
break;
|
|||
|
}
|
|||
|
offset -= volumeSize;
|
|||
|
}
|
|||
|
|
|||
|
p = _ePacket;
|
|||
|
p->Length = STRIPE_SIZE;
|
|||
|
p->Offset = offset;
|
|||
|
p->CompletionRoutine = VolsetTransferSequentialCompletionRoutine;
|
|||
|
p->Thread = TransferPacket->Thread;
|
|||
|
p->IrpFlags = TransferPacket->IrpFlags;
|
|||
|
p->ReadPacket = TransferPacket->ReadPacket;
|
|||
|
p->MasterPacket = TransferPacket;
|
|||
|
p->VolumeSet = this;
|
|||
|
p->WhichMember = i;
|
|||
|
|
|||
|
if (p->Length > TransferPacket->Length) {
|
|||
|
p->Length = TransferPacket->Length;
|
|||
|
}
|
|||
|
|
|||
|
if (p->Offset + p->Length > volumeSize) {
|
|||
|
p->Length = (ULONG) (volumeSize - p->Offset);
|
|||
|
}
|
|||
|
|
|||
|
IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl,
|
|||
|
MmGetMdlVirtualAddress(TransferPacket->Mdl), p->Length);
|
|||
|
|
|||
|
TRANSFER(p);
|
|||
|
}
|