653 lines
18 KiB
C
653 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
volset.c
|
||
|
||
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)
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ntddk.h"
|
||
#include "ftdisk.h"
|
||
|
||
#ifdef POOL_TAGGING
|
||
#ifdef ExAllocatePool
|
||
#undef ExAllocatePool
|
||
#endif
|
||
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,' VtF')
|
||
#endif
|
||
|
||
#define FTDUP_IRP 1
|
||
|
||
//
|
||
// Short hand definitions for state information saved in the stack
|
||
// reserved for FT use for Irp's passed to lower drivers. The Irp
|
||
// and Mdl flags are set in Ftp..() routines located in ftutil.c
|
||
//
|
||
|
||
#define VolSetAllocatedSystemBuffer Parameters.Others.Argument2
|
||
|
||
|
||
BOOLEAN
|
||
VsetpFindSetLocation(
|
||
IN OUT PDEVICE_EXTENSION *DeviceExtension,
|
||
IN OUT PLARGE_INTEGER IoOffset,
|
||
IN OUT PULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION extension = *DeviceExtension;
|
||
LARGE_INTEGER logicalEnd = extension->FtUnion.Identity.PartitionLength;
|
||
LARGE_INTEGER ioStart = *IoOffset;
|
||
LARGE_INTEGER offset = *IoOffset;
|
||
LARGE_INTEGER ioEnd;
|
||
|
||
ioEnd.QuadPart = ioStart.QuadPart + *Length;
|
||
|
||
//
|
||
// The list of partitions that comprise the volume set is searched
|
||
// to determine where the I/O belongs. This can be broken into the
|
||
// following parts:
|
||
//
|
||
// 1. The I/O ends in the current partition. Therefore is
|
||
// contained in this partition.
|
||
//
|
||
// 2. The I/O does not start in the current partition. Continue
|
||
// to the next partition.
|
||
//
|
||
// 3. The I/O starts in this partition, but did not end in this
|
||
// partition. This I/O must be broken into two parts, the first
|
||
// for the current partition and the next for the following
|
||
// partition.
|
||
//
|
||
|
||
while (extension != NULL) {
|
||
|
||
DebugPrint((5,
|
||
"VspFindSetLocation: ioStart %x:%x ioEnd %x:%x - End %x:%x\n",
|
||
ioStart.HighPart,
|
||
ioStart.LowPart,
|
||
ioEnd.HighPart,
|
||
ioEnd.LowPart,
|
||
logicalEnd.HighPart,
|
||
logicalEnd.LowPart));
|
||
|
||
//
|
||
// If the end of the I/O operation is before the end of this partition,
|
||
// then the I/O occurs here.
|
||
//
|
||
|
||
if (logicalEnd.QuadPart >= ioEnd.QuadPart) {
|
||
|
||
*DeviceExtension = extension;
|
||
*IoOffset = offset;
|
||
|
||
//
|
||
// Length is the same as that passed in.
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// If the start of the I/O is greater than the logical end of this
|
||
// partition then the I/O is in the next partition.
|
||
//
|
||
|
||
if (ioStart.QuadPart >= logicalEnd.QuadPart) {
|
||
|
||
//
|
||
// I/O does not start in this partition.
|
||
// Update the current offset for the I/O to reflect its relative
|
||
// position to the next partition.
|
||
//
|
||
|
||
offset.QuadPart -= extension->FtUnion.Identity.PartitionLength.QuadPart;
|
||
|
||
//
|
||
// Move to the next member of the volume set. If it is null
|
||
// the while loop will exit and an error will be returned.
|
||
// If it is not null the concept of where the logical end for
|
||
// the volume set is updated to include the next member partition.
|
||
//
|
||
|
||
extension = extension->NextMember;
|
||
|
||
if (extension != NULL) {
|
||
|
||
//
|
||
// update the logical end of the complete volume set with
|
||
// the size of this partition.
|
||
//
|
||
|
||
logicalEnd.QuadPart += extension->FtUnion.Identity.PartitionLength.QuadPart;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// This I/O splits two members of the volume set.
|
||
//
|
||
|
||
*DeviceExtension = extension;
|
||
*IoOffset = offset;
|
||
*Length = (ULONG) (logicalEnd.QuadPart - ioStart.QuadPart);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
VolumeSetReadWrite(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is given control from the FtDiskReadWrite() routine
|
||
whenever an I/O request is made for a volume set. Activity includes
|
||
determining the partition for the I/O and creating new Irps if
|
||
needed.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension - The device extension for the mirror.
|
||
Irp - The i/o request.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP newIrp;
|
||
PIO_STACK_LOCATION newIrpStack;
|
||
PVOID dataBuffer;
|
||
PDEVICE_EXTENSION zeroExtension = DeviceObject->DeviceExtension;
|
||
PDEVICE_EXTENSION deviceExtension = zeroExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PIO_STACK_LOCATION ftIrpStack = IoGetNextIrpStackLocation(Irp);
|
||
ULONG ioLength = irpStack->Parameters.Write.Length;
|
||
LARGE_INTEGER offset = irpStack->Parameters.Write.ByteOffset;
|
||
LARGE_INTEGER zero;
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// This routine always returns STATUS_PENDING. The master Irp must
|
||
// be marked as pending or the I/O system will throw it away.
|
||
//
|
||
|
||
IoMarkIrpPending(Irp);
|
||
|
||
if (VsetpFindSetLocation(&deviceExtension, &offset, &ioLength) == TRUE) {
|
||
|
||
//
|
||
// The I/O is legal within the volume set.
|
||
//
|
||
|
||
if (ioLength == irpStack->Parameters.Write.Length) {
|
||
|
||
//
|
||
// I/O is completely contained within this member of the
|
||
// volume set.
|
||
//
|
||
|
||
newIrp = FtpDuplicateIrp(deviceExtension->TargetObject,
|
||
Irp);
|
||
|
||
//
|
||
// Adjust the beginning offset for the I/O.
|
||
// This is in the NEXT stack, or the stack for the lower driver.
|
||
//
|
||
|
||
newIrpStack = IoGetNextIrpStackLocation(newIrp);
|
||
newIrpStack->Parameters.Write.ByteOffset = offset;
|
||
|
||
//
|
||
// Set completion routine callback for the Irp.
|
||
//
|
||
|
||
IoSetCompletionRoutine(newIrp,
|
||
(PIO_COMPLETION_ROUTINE)VolumeSetIoCompletion,
|
||
(PVOID) zeroExtension,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
DebugPrint((3,
|
||
"VolumeSetReadWrite: %s volume IRP=%x, newIrp=%x, O=%x:%x,L=%x\n",
|
||
(irpStack->MajorFunction == IRP_MJ_READ) ? "Reading" : "Writing",
|
||
Irp,
|
||
newIrp,
|
||
offset.HighPart,
|
||
offset.LowPart,
|
||
ioLength));
|
||
|
||
ftIrpStack->FtOrgIrpCount = (PVOID) 1;
|
||
IoCallDriver(deviceExtension->TargetObject, newIrp);
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
//
|
||
// I/O starts in this partition, but ends in the next partition.
|
||
// Calculate how much is in the current partition and create an
|
||
// Irp for the device. Must adjust the length of the I/O operation
|
||
// to end in this partition in the stack area for the NEXT driver.
|
||
//
|
||
|
||
dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
|
||
newIrp = FtpDuplicatePartialIrp(deviceExtension->DeviceObject,
|
||
Irp,
|
||
dataBuffer,
|
||
offset,
|
||
ioLength);
|
||
//
|
||
// Mark the original Irp that two I/Os are to occur and start
|
||
// the first I/O.
|
||
//
|
||
|
||
DebugPrint((3,
|
||
"VolumeSetReadWrite: %s split, IRP=%x, newIrp=%x, O=%x:%x,L=%x\n",
|
||
(irpStack->MajorFunction == IRP_MJ_READ) ? "Read" : "Write",
|
||
Irp,
|
||
newIrp,
|
||
offset.HighPart,
|
||
offset.LowPart,
|
||
ioLength));
|
||
|
||
if (deviceExtension->NextMember == NULL) {
|
||
|
||
//
|
||
// This I/O extends beyond the end of the volume set.
|
||
//
|
||
|
||
ftIrpStack->FtOrgIrpCount = (PVOID) 1;
|
||
} else {
|
||
ftIrpStack->FtOrgIrpCount = (PVOID) 2;
|
||
}
|
||
|
||
//
|
||
// Set completion routine callback for the Irp.
|
||
//
|
||
|
||
IoSetCompletionRoutine(newIrp,
|
||
(PIO_COMPLETION_ROUTINE)VolumeSetIoCompletion,
|
||
(PVOID) zeroExtension,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
(VOID) IoCallDriver(deviceExtension->TargetObject, newIrp);
|
||
|
||
//
|
||
// The second I/O starts at offset zero for the partition and
|
||
// is the remaining size of the I/O.
|
||
//
|
||
|
||
deviceExtension = deviceExtension->NextMember;
|
||
if (deviceExtension == NULL) {
|
||
|
||
//
|
||
// The completion routine will handle the partial read status.
|
||
//
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
//
|
||
// Calculate starting memory offset for second I/O.
|
||
//
|
||
|
||
dataBuffer = (PUCHAR)dataBuffer + ioLength;
|
||
|
||
//
|
||
// Calculate the second I/O length.
|
||
//
|
||
|
||
ioLength = irpStack->Parameters.Write.Length - ioLength;
|
||
|
||
//
|
||
// Allocate and set up a new Irp.
|
||
//
|
||
|
||
zero.QuadPart = 0;
|
||
newIrp = FtpDuplicatePartialIrp(deviceExtension->DeviceObject,
|
||
Irp,
|
||
dataBuffer,
|
||
zero,
|
||
ioLength);
|
||
|
||
DebugPrint((3,
|
||
"VolumeSetReadWrite: %s 2nd IRP=0x%x,newIrp=0x%x, O=%x:%x,L=%x\n",
|
||
(irpStack->MajorFunction == IRP_MJ_READ) ? "Read" : "Write",
|
||
Irp,
|
||
newIrp,
|
||
0,
|
||
0,
|
||
ioLength));
|
||
IoSetCompletionRoutine(newIrp,
|
||
(PIO_COMPLETION_ROUTINE)VolumeSetIoCompletion,
|
||
(PVOID) zeroExtension,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
(VOID) IoCallDriver(deviceExtension->TargetObject, newIrp);
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
DebugPrint((2,"VolumeSetReadWrite: beyond volume set.\n"));
|
||
|
||
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||
FtpCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
VolumeSetIoCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when an IRP completes for a volume set.
|
||
The IRP could be for any member of the volume set. In the original
|
||
IRP there is a count of outstanding IRPs.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - FT device object.
|
||
Irp - the completed IRP.
|
||
Context - the FT deviceExtension for the IRP.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS == STATUS_MORE_PROCESSING_REQUIRED
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG irpCount;
|
||
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) Context;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PIRP masterIrp = (PIRP) irpStack->FtLowIrpMasterIrp;
|
||
PIO_STACK_LOCATION masterIrpStack = IoGetNextIrpStackLocation(masterIrp);
|
||
|
||
ASSERT(masterIrp != NULL);
|
||
|
||
DebugPrint((4,
|
||
"VolumeSetIoCompletion: I/O complete status %x for function %x\n",
|
||
Irp->IoStatus.Status,
|
||
irpStack->MajorFunction));
|
||
|
||
if (irpStack->VolSetAllocatedSystemBuffer == (PVOID) 1) {
|
||
|
||
//
|
||
// The system buffer was allocated by the volume set code.
|
||
//
|
||
|
||
ExFreePool(Irp->AssociatedIrp.SystemBuffer);
|
||
}
|
||
|
||
if (irpStack->FtLowIrpAllocatedMdl == (PVOID) 1) {
|
||
|
||
//
|
||
// The MDL in this Irp was allocated by the FT driver.
|
||
//
|
||
|
||
IoFreeMdl(Irp->MdlAddress);
|
||
}
|
||
|
||
//
|
||
// NOTE: If the first I/O fails the second I/O will continue, meaning
|
||
// a portion of the I/O request will complete that will not be
|
||
// notified to the caller. This is different from the normal one
|
||
// device case.
|
||
//
|
||
|
||
if (NT_SUCCESS(masterIrp->IoStatus.Status)) {
|
||
|
||
if (NT_SUCCESS(masterIrp->IoStatus.Status = Irp->IoStatus.Status)) {
|
||
//
|
||
// Update the information field.
|
||
//
|
||
|
||
masterIrp->IoStatus.Information += Irp->IoStatus.Information;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Store the information.
|
||
//
|
||
|
||
masterIrp->IoStatus.Information = Irp->IoStatus.Information;
|
||
}
|
||
}
|
||
|
||
IoFreeIrp(Irp);
|
||
irpCount = InterlockedDecrement((PLONG) &masterIrpStack->FtOrgIrpCount);
|
||
|
||
if (irpCount == 0) {
|
||
|
||
//
|
||
// I/O processing is complete. Return the master IRP.
|
||
//
|
||
|
||
DebugPrint((2,
|
||
"VolumeSetIoCompletion: Completed (0x%x) 0x%x status %x info 0x%x\n",
|
||
Irp,
|
||
masterIrp,
|
||
masterIrp->IoStatus.Status,
|
||
masterIrp->IoStatus.Information));
|
||
|
||
FtpCompleteRequest(masterIrp, IO_DISK_INCREMENT);
|
||
} else {
|
||
|
||
//
|
||
// Multiple I/O. One item has completed. Decrement the request
|
||
// count, free this Irp and return indicating that more work is needed
|
||
// to complete the master request.
|
||
//
|
||
|
||
DebugPrint((2,
|
||
"VolumeSetIoCompletion: First I/O 0x%x I/O complete (%x).\n",
|
||
Irp,
|
||
masterIrp->IoStatus.Status));
|
||
}
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
VolumeSetVerify(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the device control to verify an area
|
||
of disk within a volume set is performed.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object for the mirror.
|
||
Irp - The i/o request.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP newIrp;
|
||
PIO_STACK_LOCATION newIrpStack;
|
||
PDEVICE_EXTENSION zeroExtension = DeviceObject->DeviceExtension;
|
||
PDEVICE_EXTENSION deviceExtension = zeroExtension;
|
||
PIO_STACK_LOCATION ftIrpStack = IoGetNextIrpStackLocation(Irp);
|
||
PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
|
||
LARGE_INTEGER offset = verifyInfo->StartingOffset;
|
||
ULONG length = verifyInfo->Length;
|
||
BOOLEAN twoIrps = FALSE;
|
||
|
||
if (VsetpFindSetLocation(&deviceExtension, &offset, &length) == FALSE) {
|
||
|
||
DebugPrint((2,"VolumeSetVerify: beyond volume set.\n"));
|
||
|
||
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||
FtpCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = 0;
|
||
newIrp = FtpDuplicateIrp(deviceExtension->TargetObject,
|
||
Irp);
|
||
ASSERT(newIrp != NULL);
|
||
|
||
IoMarkIrpPending(Irp);
|
||
|
||
//
|
||
// Set completion routine callback for both Irps.
|
||
//
|
||
|
||
IoSetCompletionRoutine(newIrp,
|
||
(PIO_COMPLETION_ROUTINE)VolumeSetIoCompletion,
|
||
(PVOID) zeroExtension,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
|
||
|
||
//
|
||
// Update the offset for the verify since it may have changed.
|
||
//
|
||
|
||
verifyInfo->StartingOffset = offset;
|
||
|
||
if (length == verifyInfo->Length) {
|
||
|
||
//
|
||
// Only the one Irp.
|
||
//
|
||
|
||
ftIrpStack->FtOrgIrpCount = (PVOID) 1;
|
||
newIrp->AssociatedIrp.SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||
newIrpStack->VolSetAllocatedSystemBuffer = (PVOID) 0;
|
||
} else {
|
||
PVERIFY_INFORMATION newVerify = ExAllocatePool(NonPagedPool,
|
||
sizeof(VERIFY_INFORMATION));
|
||
|
||
//
|
||
// There will be two Irp's must make a copy of the system
|
||
// buffer for one of the device drivers.
|
||
//
|
||
|
||
twoIrps = TRUE;
|
||
ftIrpStack->FtOrgIrpCount = (PVOID) 2;
|
||
newIrp->AssociatedIrp.SystemBuffer = (PVOID) newVerify;
|
||
|
||
*newVerify= *verifyInfo;
|
||
newVerify->Length = length;
|
||
newIrpStack->VolSetAllocatedSystemBuffer = (PVOID) 1;
|
||
|
||
//
|
||
// Now update the current parameter structure for the second Irp.
|
||
//
|
||
|
||
verifyInfo->StartingOffset.HighPart = 0;
|
||
verifyInfo->StartingOffset.LowPart = 0;
|
||
verifyInfo->Length = verifyInfo->Length - length;
|
||
DebugPrint((2,
|
||
"VolumeSetVerify: First extension %x with %x length %x\n",
|
||
deviceExtension,
|
||
newIrp,
|
||
length));
|
||
}
|
||
|
||
DebugPrint((4, "VolumeSetVerify: Starting extension %x with %x length %x\n",
|
||
deviceExtension,
|
||
newIrp,
|
||
length));
|
||
(VOID) IoCallDriver(deviceExtension->TargetObject, newIrp);
|
||
|
||
if (twoIrps == TRUE) {
|
||
|
||
//
|
||
// Need to perform the remaining verify.
|
||
//
|
||
|
||
deviceExtension = deviceExtension->NextMember;
|
||
|
||
if (deviceExtension != NULL) {
|
||
newIrp = FtpDuplicateIrp(deviceExtension->TargetObject,
|
||
Irp);
|
||
IoSetCompletionRoutine(newIrp,
|
||
(PIO_COMPLETION_ROUTINE)VolumeSetIoCompletion,
|
||
(PVOID) zeroExtension,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
|
||
newIrpStack->VolSetAllocatedSystemBuffer = (PVOID) 0;
|
||
newIrp->AssociatedIrp.SystemBuffer= Irp->AssociatedIrp.SystemBuffer;
|
||
DebugPrint((2,
|
||
"VolumeSetVerify: Second extension %x with %x length %x\n",
|
||
deviceExtension,
|
||
newIrp,
|
||
verifyInfo->Length));
|
||
(VOID) IoCallDriver(deviceExtension->TargetObject, newIrp);
|
||
}
|
||
}
|
||
return STATUS_PENDING;
|
||
}
|