Windows-Server-2003/drivers/storage/newft/partitio.cxx

1518 lines
32 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:
partitio.cxx
Abstract:
This module contains the code specific to partitions 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:
--*/
extern "C" {
#include <ntddk.h>
}
#include <ftdisk.h>
class REPLACE_BAD_SECTOR_CONTEXT : public WORK_QUEUE_ITEM {
public:
PDEVICE_OBJECT TargetObject;
PIRP Irp;
};
typedef REPLACE_BAD_SECTOR_CONTEXT *PREPLACE_BAD_SECTOR_CONTEXT;
NTSTATUS
PartitionBroadcastIrpCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID CompletionContext
);
#ifdef ALLOC_PRAGMA
#pragma code_seg("PAGE")
#endif
NTSTATUS
PARTITION::Initialize(
IN OUT PROOT_EXTENSION RootExtension,
IN FT_LOGICAL_DISK_ID LogicalDiskId,
IN OUT PDEVICE_OBJECT TargetObject,
IN OUT PDEVICE_OBJECT WholeDiskPdo
)
/*++
Routine Description:
Initialize routine for FT_VOLUME of type PARTITION.
Arguments:
RootExtension - Supplies the root device extension.
LogicalDiskId - Supplies the logical disk id for this volume.
TargetObject - Supplies the partition to which transfer requests are
forwarded to.
WholeDiskPdo - Supplies the whole disk for this partition.
Return Value:
None.
--*/
{
KEVENT event;
PIRP irp;
DISK_GEOMETRY geometry;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
ULONG diskNumber, otherDiskNumber;
LONGLONG offset, partitionSize;
FT_VOLUME::Initialize(RootExtension, LogicalDiskId);
_targetObject = TargetObject;
_wholeDiskPdo = WholeDiskPdo;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
TargetObject, NULL, 0, &geometry,
sizeof(geometry), FALSE, &event,
&ioStatus);
if (!irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(TargetObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (!NT_SUCCESS(status)) {
return status;
}
_sectorSize = geometry.BytesPerSector;
status = FtpQueryPartitionInformation(RootExtension, TargetObject,
&diskNumber, &_partitionOffset,
NULL, NULL, &_partitionLength,
NULL, NULL, NULL, NULL);
if (!NT_SUCCESS(status)) {
return status;
}
if (!_diskInfoSet->QueryFtPartitionInformation(LogicalDiskId,
&offset, NULL,
&otherDiskNumber, NULL,
&partitionSize)) {
return STATUS_INVALID_PARAMETER;
}
if (partitionSize > 0 && partitionSize <= _partitionLength) {
_partitionLength = partitionSize;
}
if (offset != _partitionOffset || diskNumber != otherDiskNumber) {
return STATUS_INVALID_PARAMETER;
}
_emergencyIrp = IoAllocateIrp(_targetObject->StackSize, FALSE);
if (!_emergencyIrp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
_emergencyIrpInUse = FALSE;
InitializeListHead(&_emergencyIrpQueue);
return STATUS_SUCCESS;
}
FT_LOGICAL_DISK_TYPE
PARTITION::QueryLogicalDiskType(
)
/*++
Routine Description:
This routine returns the type of the logical disk.
Arguments:
None.
Return Value:
The type of the logical disk.
--*/
{
return FtPartition;
}
NTSTATUS
PARTITION::OrphanMember(
IN USHORT MemberNumber,
IN FT_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID Context
)
/*++
Routine Description:
This routine tries to orphan the given member of this logical disk.
A completion routine will be called if and only if this attempt is successful.
Arguments:
MemberNumber - Supplies the member number to orphan.
CompletionRoutine - Supplies the completion routine.
Context - Supplies the completion routine context.
Return Value:
NTSTATUS
--*/
{
return STATUS_INVALID_PARAMETER;
}
NTSTATUS
PARTITION::RegenerateMember(
IN USHORT MemberNumber,
IN OUT PFT_VOLUME NewMember,
IN FT_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID Context
)
/*++
Routine Description:
This routine regenerates the given member of this volume with
the given volume.
Arguments:
MemberNumber - Supplies the member number to regenerate.
NewMember - Supplies the new member to regenerate to.
CompletionRoutine - Supplies the completion routine.
Context - Supplies the completion routine context.
Return Value:
NTSTATUS
--*/
{
return STATUS_INVALID_PARAMETER;
}
VOID
PartitionReplaceBadSectorWorker(
IN PVOID Context
)
{
PREPLACE_BAD_SECTOR_CONTEXT context = (PREPLACE_BAD_SECTOR_CONTEXT) Context;
IoCallDriver(context->TargetObject, context->Irp);
}
VOID
PARTITION::StopSyncOperations(
)
/*++
Routine Description:
This routine stops all sync operations.
Arguments:
None.
Return Value:
None.
--*/
{
}
VOID
PARTITION::BroadcastIrp(
IN PIRP Irp,
IN FT_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID Context
)
/*++
Routine Description:
This routine broadcasts a copy of the given IRP to every partition that
is a member of the logical disk.
Arguments:
Irp - Supplies the I/O request packet.
CompletionRoutine - Supplies the routine to be called when the operation
completes.
Context - Supplies the completion routine context.
Return Value:
None.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp, sp;
PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
irp = IoAllocateIrp(_targetObject->StackSize, FALSE);
if (!irp) {
CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
return;
}
completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT)
ExAllocatePool(NonPagedPool,
sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
if (!completionContext) {
IoFreeIrp(irp);
CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
return;
}
completionContext->CompletionRoutine = CompletionRoutine;
completionContext->Context = Context;
irpSp = IoGetNextIrpStackLocation(irp);
sp = IoGetCurrentIrpStackLocation(Irp);
*irpSp = *sp;
IoSetCompletionRoutine(irp, PartitionBroadcastIrpCompletionRoutine,
completionContext, TRUE, TRUE, TRUE);
IoCallDriver(_targetObject, irp);
}
PFT_VOLUME
PARTITION::GetParentLogicalDisk(
IN PFT_VOLUME Volume
)
/*++
Routine Description:
This routine returns the parent of the given logical disk within
this volume.
Arguments:
Volume - Supplies the sub-volume of which we are looking for the parent.
Return Value:
The parent volume or NULL;
--*/
{
return NULL;
}
VOID
PARTITION::SetDirtyBit(
IN BOOLEAN IsDirty,
IN FT_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID Context
)
/*++
Routine Description:
This routine sets the dirty bit on the volume. This bit is used at
startup to determine whether or not there was a clean shutdown.
Arguments:
IsDirty - Supplies the value of the dirty bit.
Return Value:
None.
--*/
{
if (CompletionRoutine) {
CompletionRoutine(Context, STATUS_SUCCESS);
}
}
NTSTATUS
PARTITION::CheckIo(
OUT PBOOLEAN IsIoOk
)
/*++
Routine Description:
This routine returns whether or not IO is possible on the given
partition.
Arguments:
IsIoOk - Returns the state of IO.
Return Value:
NTSTATUS
--*/
{
PVOID buffer;
LARGE_INTEGER offset;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
buffer = ExAllocatePool(NonPagedPoolCacheAligned, PAGE_SIZE);
if (!buffer) {
return STATUS_INSUFFICIENT_RESOURCES;
}
offset.QuadPart = 0;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, _targetObject,
buffer, PAGE_SIZE, &offset, &event,
&ioStatus);
if (!irp) {
ExFreePool(buffer);
return STATUS_INSUFFICIENT_RESOURCES;
}
irpSp = IoGetNextIrpStackLocation(irp);
irpSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
status = IoCallDriver(_targetObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (FsRtlIsTotalDeviceFailure(status)) {
*IsIoOk = FALSE;
} else {
*IsIoOk = TRUE;
}
ExFreePool(buffer);
return STATUS_SUCCESS;
}
NTSTATUS
PARTITION::SetPartitionType(
IN UCHAR PartitionType
)
/*++
Routine Description:
This routine sets the partition type on all the members of the
FT set.
Arguments:
PartitionType - Supplies the partition type.
Return Value:
NTSTATUS
--*/
{
KEVENT event;
SET_PARTITION_INFORMATION partInfo;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
partInfo.PartitionType = (PartitionType | 0x80);
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_PARTITION_INFO,
_targetObject, &partInfo,
sizeof(partInfo), NULL, 0, FALSE,
&event, &ioStatus);
if (!irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(_targetObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
return status;
}
UCHAR
PARTITION::QueryPartitionType(
)
/*++
Routine Description:
This routine queries the partition type.
Arguments:
None.
Return Value:
The partition type.
--*/
{
KEVENT event;
PIRP irp;
PARTITION_INFORMATION partInfo;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
_targetObject, NULL, 0, &partInfo,
sizeof(partInfo), FALSE, &event,
&ioStatus);
if (!irp) {
return 0;
}
status = IoCallDriver(_targetObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (!NT_SUCCESS(status)) {
return 0;
}
return partInfo.PartitionType;
}
UCHAR
PARTITION::QueryStackSize(
)
/*++
Routine Description:
This routine queries IRP stack size.
Arguments:
None.
Return Value:
The IRP stack size.
--*/
{
return _targetObject->StackSize;
}
VOID
PARTITION::CreateLegacyNameLinks(
IN PUNICODE_STRING DeviceName
)
/*++
Routine Description:
This routine creates the \Device\HarddiskN\PartitionM links for
this object to the given device name.
Arguments:
DeviceName - Supplies the device name.
Return Value:
None.
--*/
{
NTSTATUS status;
ULONG diskNumber, partitionNumber;
WCHAR buf[80];
UNICODE_STRING symName;
status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
&diskNumber, NULL, &partitionNumber,
NULL, NULL, NULL, NULL, NULL, NULL);
if (!NT_SUCCESS(status)) {
return;
}
swprintf(buf, L"\\Device\\Harddisk%d\\Partition%d", diskNumber,
partitionNumber);
RtlInitUnicodeString(&symName, buf);
IoDeleteSymbolicLink(&symName);
if (DeviceName) {
IoCreateSymbolicLink(&symName, DeviceName);
}
}
NTSTATUS
PARTITION::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
--*/
{
NTSTATUS status;
ULONG diskNumber;
PVOLUME_PHYSICAL_OFFSET physicalOffset;
status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
&diskNumber, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
if (!NT_SUCCESS(status)) {
return status;
}
if (LogicalOffset < 0 ||
_partitionLength <= LogicalOffset) {
return STATUS_INVALID_PARAMETER;
}
physicalOffset = (PVOLUME_PHYSICAL_OFFSET) ExAllocatePool(PagedPool, sizeof(VOLUME_PHYSICAL_OFFSET));
if (!physicalOffset) {
return STATUS_INSUFFICIENT_RESOURCES;
}
physicalOffset->DiskNumber = diskNumber;
physicalOffset->Offset = _partitionOffset + LogicalOffset;
*PhysicalOffsets = physicalOffset;
*NumberOfPhysicalOffsets = 1;
return status;
}
NTSTATUS
PARTITION::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
--*/
{
NTSTATUS status;
ULONG diskNumber;
PVOLUME_PHYSICAL_OFFSET physicalOffset;
status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
&diskNumber, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
if (!NT_SUCCESS(status)) {
return status;
}
if (PhysicalOffset->DiskNumber != diskNumber ||
PhysicalOffset->Offset < _partitionOffset ||
_partitionOffset + _partitionLength <= PhysicalOffset->Offset) {
return STATUS_INVALID_PARAMETER;
}
*LogicalOffset = PhysicalOffset->Offset - _partitionOffset;
return status;
}
#ifdef ALLOC_PRAGMA
#pragma code_seg("PAGELK")
#endif
PARTITION::~PARTITION(
)
{
if (_emergencyIrp) {
IoFreeIrp(_emergencyIrp);
_emergencyIrp = NULL;
}
}
USHORT
PARTITION::QueryNumberOfMembers(
)
/*++
Routine Description:
This routine returns the number of members in this volume.
Arguments:
None.
Return Value:
0 - A volume of type partition has no members.
--*/
{
return 0;
}
PFT_VOLUME
PARTITION::GetMember(
IN USHORT MemberNumber
)
/*++
Routine Description:
This routine returns the 'MemberNumber'th member of this volume.
Arguments:
MemberNumber - Supplies the zero based member number desired.
Return Value:
A pointer to the 'MemberNumber'th member or NULL if no such member.
--*/
{
ASSERT(FALSE);
return NULL;
}
NTSTATUS
PartitionTransferCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID TransferPacket
)
/*++
Routine Description:
Completion routine for PARTITION::Transfer function.
Arguments:
Irp - Supplies the IRP.
TransferPacket - Supplies the transfer packet.
Return Value:
STATUS_MORE_PROCESSING_REQUIRED
--*/
{
PTRANSFER_PACKET transferPacket = (PTRANSFER_PACKET) TransferPacket;
PPARTITION t = (PPARTITION) transferPacket->TargetVolume;
KIRQL irql;
PLIST_ENTRY l;
PIRP irp;
PTRANSFER_PACKET p;
PIO_STACK_LOCATION irpSp;
transferPacket->IoStatus = Irp->IoStatus;
if (Irp == transferPacket->OriginalIrp) {
transferPacket->CompletionRoutine(transferPacket);
return STATUS_MORE_PROCESSING_REQUIRED;
}
if (Irp->AssociatedIrp.SystemBuffer) {
ExFreePool(Irp->AssociatedIrp.SystemBuffer);
}
if (Irp == t->_emergencyIrp) {
for (;;) {
KeAcquireSpinLock(&t->_spinLock, &irql);
if (IsListEmpty(&t->_emergencyIrpQueue)) {
t->_emergencyIrpInUse = FALSE;
KeReleaseSpinLock(&t->_spinLock, irql);
break;
}
l = RemoveHeadList(&t->_emergencyIrpQueue);
KeReleaseSpinLock(&t->_spinLock, irql);
irp = IoAllocateIrp(t->_targetObject->StackSize, FALSE);
if (!irp) {
irp = t->_emergencyIrp;
IoReuseIrp(irp, STATUS_SUCCESS);
}
p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
irpSp = IoGetNextIrpStackLocation(irp);
irp->MdlAddress = p->Mdl;
irpSp->Parameters.Write.ByteOffset.QuadPart = p->Offset;
irpSp->Parameters.Write.Length = p->Length;
if (p->ReadPacket) {
irpSp->MajorFunction = IRP_MJ_READ;
} else {
irpSp->MajorFunction = IRP_MJ_WRITE;
}
irpSp->DeviceObject = t->_targetObject;
irp->Tail.Overlay.Thread = p->Thread;
irpSp->Flags = p->IrpFlags;
IoSetCompletionRoutine(irp, PartitionTransferCompletionRoutine,
p, TRUE, TRUE, TRUE);
if (irp == Irp) {
IoCallDriver(t->_targetObject, irp);
break;
} else {
IoCallDriver(t->_targetObject, irp);
}
}
} else {
IoFreeIrp(Irp);
}
transferPacket->CompletionRoutine(transferPacket);
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
PARTITION::Transfer(
IN OUT PTRANSFER_PACKET TransferPacket
)
/*++
Routine Description:
Transfer routine for PARTITION type FT_VOLUME. Basically,
just pass the request down to the target object.
Arguments:
TransferPacket - Supplies the transfer packet.
Return Value:
None.
--*/
{
KIRQL irql;
PIRP irp;
PIO_STACK_LOCATION irpSp;
PVERIFY_INFORMATION verifyInfo;
irp = TransferPacket->OriginalIrp;
if (!irp) {
irp = IoAllocateIrp(_targetObject->StackSize, FALSE);
if (!irp) {
if (!TransferPacket->Mdl) {
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
KeAcquireSpinLock(&_spinLock, &irql);
if (_emergencyIrpInUse) {
InsertTailList(&_emergencyIrpQueue, &TransferPacket->QueueEntry);
KeReleaseSpinLock(&_spinLock, irql);
return;
}
_emergencyIrpInUse = TRUE;
KeReleaseSpinLock(&_spinLock, irql);
irp = _emergencyIrp;
IoReuseIrp(irp, STATUS_SUCCESS);
}
}
irpSp = IoGetNextIrpStackLocation(irp);
if (TransferPacket->Mdl) {
irp->MdlAddress = TransferPacket->Mdl;
irpSp->Parameters.Write.ByteOffset.QuadPart = TransferPacket->Offset;
irpSp->Parameters.Write.Length = TransferPacket->Length;
if (TransferPacket->ReadPacket) {
irpSp->MajorFunction = IRP_MJ_READ;
} else {
irpSp->MajorFunction = IRP_MJ_WRITE;
}
} else {
// Since there is no MDL, this is a verify request.
verifyInfo = (PVERIFY_INFORMATION)
ExAllocatePool(NonPagedPool, sizeof(VERIFY_INFORMATION));
if (!verifyInfo) {
IoFreeIrp(irp);
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
verifyInfo->StartingOffset.QuadPart = TransferPacket->Offset;
verifyInfo->Length = TransferPacket->Length;
irp->AssociatedIrp.SystemBuffer = verifyInfo;
irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(VERIFY_INFORMATION);
irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_DISK_VERIFY;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
}
irpSp->DeviceObject = _targetObject;
irp->Tail.Overlay.Thread = TransferPacket->Thread;
irpSp->Flags = TransferPacket->IrpFlags;
IoSetCompletionRoutine(irp, PartitionTransferCompletionRoutine,
TransferPacket, TRUE, TRUE, TRUE);
IoCallDriver(_targetObject, irp);
}
VOID
PARTITION::ReplaceBadSector(
IN OUT PTRANSFER_PACKET TransferPacket
)
/*++
Routine Description:
This routine attempts to fix the given bad sector by performing
a reassign blocks ioctl.
Arguments:
TransferPacket - Supplies the transfer packet.
Return Value:
None.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
PREASSIGN_BLOCKS badBlock;
ULONG n, size, first, i;
PREPLACE_BAD_SECTOR_CONTEXT context;
irp = IoAllocateIrp(_targetObject->StackSize, FALSE);
if (!irp) {
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
n = TransferPacket->Length/_sectorSize;
size = FIELD_OFFSET(REASSIGN_BLOCKS, BlockNumber) + n*sizeof(ULONG);
badBlock = (PREASSIGN_BLOCKS) ExAllocatePool(NonPagedPool, size);
if (!badBlock) {
IoFreeIrp(irp);
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
badBlock->Reserved = 0;
badBlock->Count = 1;
first = (ULONG) ((TransferPacket->Offset + _partitionOffset)/_sectorSize);
for (i = 0; i < n; i++) {
badBlock->BlockNumber[i] = first + i;
}
irp->AssociatedIrp.SystemBuffer = badBlock;
irpSp = IoGetNextIrpStackLocation(irp);
irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
irpSp->Parameters.DeviceIoControl.InputBufferLength = size;
irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_DISK_REASSIGN_BLOCKS;
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpSp->DeviceObject = _targetObject;
irp->Tail.Overlay.Thread = TransferPacket->Thread;
irpSp->Flags = TransferPacket->IrpFlags;
IoSetCompletionRoutine(irp, PartitionTransferCompletionRoutine,
TransferPacket, TRUE, TRUE, TRUE);
context = (PREPLACE_BAD_SECTOR_CONTEXT)
ExAllocatePool(NonPagedPool, sizeof(REPLACE_BAD_SECTOR_CONTEXT));
if (!context) {
ExFreePool(badBlock);
IoFreeIrp(irp);
TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
TransferPacket->IoStatus.Information = 0;
TransferPacket->CompletionRoutine(TransferPacket);
return;
}
ExInitializeWorkItem(context, PartitionReplaceBadSectorWorker, context);
context->TargetObject = _targetObject;
context->Irp = irp;
FtpQueueWorkItem(_rootExtension, context);
}
VOID
PARTITION::StartSyncOperations(
IN BOOLEAN RegenerateOrphans,
IN FT_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID Context
)
/*++
Routine Description:
This routine restarts any regenerate or initialize requests that
were suspended because of a reboot. The volume examines the member
state of all of its constituents and restarts any regenerations pending.
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.
--*/
{
CompletionRoutine(Context, STATUS_SUCCESS);
}
NTSTATUS
PartitionBroadcastIrpCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID CompletionContext
)
/*++
Routine Description:
Completion routine for PARTITION::BroadcastIrp functions.
Arguments:
Irp - Supplies the IRP.
CompletionContext - Supplies the completion context.
Return Value:
STATUS_MORE_PROCESSING_REQUIRED
--*/
{
PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT) CompletionContext;
completionContext->CompletionRoutine(completionContext->Context,
Irp->IoStatus.Status);
IoFreeIrp(Irp);
ExFreePool(CompletionContext);
return STATUS_MORE_PROCESSING_REQUIRED;
}
ULONG
PARTITION::QuerySectorSize(
)
/*++
Routine Description:
Returns the sector size for the volume.
Arguments:
None.
Return Value:
The volume sector size in bytes.
--*/
{
return _sectorSize;
}
LONGLONG
PARTITION::QueryVolumeSize(
)
/*++
Routine Description:
Returns the number of bytes on the entire volume.
Arguments:
None.
Return Value:
The volume size in bytes.
--*/
{
return _partitionLength;
}
PFT_VOLUME
PARTITION::GetContainedLogicalDisk(
IN FT_LOGICAL_DISK_ID LogicalDiskId
)
/*++
Routine Description:
This routine returns TRUE if the given logical disk id
represents this logical disk or if this logical disk contains
the given logical disk id either directly or indirectly.
Arguments:
LogicalDiskId - Supplies the logical disk id that we are searching for.
Return Value:
FALSE - The given logical disk id is not contained in this logical disk.
TRUE - The given logical disk id is contained in this logical disk.
--*/
{
if (LogicalDiskId == QueryLogicalDiskId()) {
return this;
}
return NULL;
}
PFT_VOLUME
PARTITION::GetContainedLogicalDisk(
IN PDEVICE_OBJECT TargetObject
)
/*++
Routine Description:
This routine returns TRUE if the given logical disk id
represents this logical disk or if this logical disk contains
the given logical disk id either directly or indirectly.
Arguments:
TargetObject - Supplies the target object.
Return Value:
FALSE - The given logical disk id is not contained in this logical disk.
TRUE - The given logical disk id is contained in this logical disk.
--*/
{
if (TargetObject == _targetObject) {
return this;
}
return NULL;
}
PFT_VOLUME
PARTITION::GetContainedLogicalDisk(
IN ULONG Signature,
IN LONGLONG Offset
)
/*++
Routine Description:
This routine returns TRUE if the given logical disk id
represents this logical disk or if this logical disk contains
the given logical disk id either directly or indirectly.
Arguments:
Signature - Supplies the signature.
Offset - Supplies the partition offset.
Return Value:
FALSE - The given logical disk id is not contained in this logical disk.
TRUE - The given logical disk id is contained in this logical disk.
--*/
{
if (Offset != _partitionOffset) {
return NULL;
}
if (Signature == FtpQueryDiskSignature(_wholeDiskPdo)) {
return this;
}
return NULL;
}
VOID
PARTITION::SetMember(
IN USHORT MemberNumber,
IN PFT_VOLUME Member
)
/*++
Routine Description:
This routine sets the given member in this volume.
Arguments:
MemberNumber - Supplies the member number.
Member - Supplies the member.
Return Value:
None.
--*/
{
ASSERT(FALSE);
}
BOOLEAN
PARTITION::IsComplete(
IN BOOLEAN IoPending
)
/*++
Routine Description:
This routine computes whether or not this volume has either all
(if IoPending is FALSE) of its members or enough (if IoPending is TRUE) of
its members.
Arguments:
IoPending - Supplies whether or not there is IO pending.
Return Value:
None.
--*/
{
return TRUE;
}
VOID
PARTITION::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.
--*/
{
}
ULONG
PARTITION::QueryNumberOfPartitions(
)
/*++
Routine Description:
This routine returns the number of partitions covered by this volume
set.
Arguments:
None.
Return Value:
The number of partitions covered by this volume set.
--*/
{
return 1;
}
PDEVICE_OBJECT
PARTITION::GetLeftmostPartitionObject(
)
{
return _targetObject;
}
NTSTATUS
PARTITION::QueryDiskExtents(
OUT PDISK_EXTENT* DiskExtents,
OUT PULONG NumberOfDiskExtents
)
/*++
Routine Description:
This routine returns an array of disk extents that describe the
location of this volume.
Arguments:
DiskExtents - Returns the disk extents.
NumberOfDiskExtents - Returns the number of disk extents.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
ULONG diskNumber;
PDISK_EXTENT diskExtent;
status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
&diskNumber, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
if (!NT_SUCCESS(status)) {
return status;
}
diskExtent = (PDISK_EXTENT) ExAllocatePool(PagedPool, sizeof(DISK_EXTENT));
if (!diskExtent) {
return STATUS_INSUFFICIENT_RESOURCES;
}
diskExtent->DiskNumber = diskNumber;
diskExtent->StartingOffset.QuadPart = _partitionOffset;
diskExtent->ExtentLength.QuadPart = _partitionLength;
*DiskExtents = diskExtent;
*NumberOfDiskExtents = 1;
return status;
}
BOOLEAN
PARTITION::QueryVolumeState(
IN PFT_VOLUME Volume,
OUT PFT_MEMBER_STATE State
)
/*++
Routine Description:
This routine returns the state of the given volume considered as a
member of this volume.
Arguments:
Volume - Supplies the volume to query the state for.
State - Returns the state.
Return Value:
FALSE - The given Volume is not a member of this volume.
TRUE - The state was successfully computed.
--*/
{
if (Volume != this) {
return FALSE;
}
*State = FtMemberHealthy;
return TRUE;
}