Skip to content

Commit

Permalink
[SETUPLIB] Don't immediately unmount volumes when deleting partitions…
Browse files Browse the repository at this point in the history
…... (reactos#7259)

...but wait until the partitions are actually updated on disk.

CORE-13525

DeletePartition() deletes partitions only in the virtual partitions list
in memory; the partitions still exist on the disk and are written only
later when committing all partition changes.

Thus, we do the same for file system volumes that lay on top of these
partitions being deleted: we move the linked VOLENTRY structures to a
list of "pending volumes to unmount", while they still actually stay
mounted on the system. Only when partition changes are about to be
committed to disk, is the "pending volumes to unmount" list processed
and the volumes actually unmounted first.
  • Loading branch information
HBelusca committed Nov 9, 2024
1 parent a17b6e9 commit 7a228d3
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 20 deletions.
70 changes: 52 additions & 18 deletions base/setup/lib/utils/partlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,7 @@ CreatePartitionList(VOID)
InitializeListHead(&List->DiskListHead);
InitializeListHead(&List->BiosDiskListHead);
InitializeListHead(&List->VolumesList);
InitializeListHead(&List->PendingUnmountVolumesList);

/*
* Enumerate the disks seen by the BIOS; this will be used later
Expand Down Expand Up @@ -2075,6 +2076,7 @@ DestroyPartitionList(
PDISKENTRY DiskEntry;
PBIOSDISKENTRY BiosDiskEntry;
PPARTENTRY PartEntry;
PVOLENTRY VolumeEntry;
PLIST_ENTRY Entry;

/* Release disk and partition info */
Expand Down Expand Up @@ -2118,6 +2120,14 @@ DestroyPartitionList(
RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
}

/* Release the pending volumes info */
while (!IsListEmpty(&List->PendingUnmountVolumesList))
{
Entry = RemoveHeadList(&List->PendingUnmountVolumesList);
VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
RtlFreeHeap(ProcessHeap, 0, VolumeEntry);
}

/* Release list head */
RtlFreeHeap(ProcessHeap, 0, List);
}
Expand Down Expand Up @@ -2964,34 +2974,43 @@ DismountPartition(
_In_ PPARTLIST List,
_In_ PPARTENTRY PartEntry)
{
NTSTATUS Status;
PVOLENTRY Volume = PartEntry->Volume;

ASSERT(PartEntry->DiskEntry->PartList == List);

/* Check whether the partition is valid and was mounted by the system */
if (!PartEntry->IsPartitioned ||
IsContainerPartition(PartEntry->PartitionType) ||
!IsRecognizedPartition(PartEntry->PartitionType) ||
!Volume || Volume->FormatState == UnknownFormat ||
if (Volume)
{
/* Partition validation checks */
ASSERT(Volume->PartEntry == PartEntry);
ASSERT(PartEntry->IsPartitioned);
ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
ASSERT(!IsContainerPartition(PartEntry->PartitionType));

/* Dismount the basic volume: unlink the volume from the list */
PartEntry->Volume = NULL;
Volume->PartEntry = NULL;
RemoveEntryList(&Volume->ListEntry);

/* Check whether the volume was mounted */
// NOTE: If FormatState == Unformatted but *FileSystem != 0 this means
// it has been usually mounted with RawFS and thus needs to be dismounted.
PartEntry->PartitionNumber == 0)
// it has usually been mounted with RawFS and thus needs to be dismounted.
if (Volume->New || (Volume->FormatState == UnknownFormat))
{
/* The volume is not mounted and can be deleted */
RtlFreeHeap(ProcessHeap, 0, Volume);
Volume = NULL;
}
}
if (!Volume)
{
/* The partition is not mounted, so just return success */
return STATUS_SUCCESS;
}

ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
ASSERT(Volume->PartEntry == PartEntry);

/* Unlink the basic volume from the volumes list and dismount it */
PartEntry->Volume = NULL;
Volume->PartEntry = NULL;
RemoveEntryList(&Volume->ListEntry);
Status = DismountVolume(&Volume->Info, TRUE);
RtlFreeHeap(ProcessHeap, 0, Volume);
return Status;
/* Dismount the basic volume, linking it into the list of volumes to unmount */
// return DismountVolume(&Volume->Info, TRUE); // For when immediate operation mode is supported.
InsertTailList(&List->PendingUnmountVolumesList, &Volume->ListEntry);
return STATUS_SUCCESS;
}

BOOLEAN
Expand Down Expand Up @@ -3758,6 +3777,21 @@ WritePartitionsToDisk(
if (!List)
return TRUE;

/* Unmount all the pending volumes */
Status = STATUS_SUCCESS;
while (!IsListEmpty(&List->PendingUnmountVolumesList))
{
NTSTATUS UnmountStatus;
Entry = RemoveHeadList(&List->PendingUnmountVolumesList);
Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
UnmountStatus = DismountVolume(&Volume->Info, TRUE);
if (!NT_SUCCESS(UnmountStatus))
Status = UnmountStatus;
RtlFreeHeap(ProcessHeap, 0, Volume);
}
if (!NT_SUCCESS(Status))
return FALSE;

/* Write all the partitions to all the disks */
for (Entry = List->DiskListHead.Flink;
Entry != &List->DiskListHead;
Expand Down
5 changes: 3 additions & 2 deletions base/setup/lib/utils/partlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ typedef enum _FORMATSTATE
typedef struct _PARTENTRY PARTENTRY, *PPARTENTRY;
typedef struct _VOLENTRY
{
LIST_ENTRY ListEntry; ///< Entry in VolumesList
LIST_ENTRY ListEntry; ///< Entry in VolumesList or PendingUnmountVolumesList

VOLINFO Info;
FORMATSTATE FormatState;
Expand Down Expand Up @@ -184,7 +184,8 @@ typedef struct _PARTLIST
LIST_ENTRY BiosDiskListHead;

/* (Basic) Volumes management */
LIST_ENTRY VolumesList;
LIST_ENTRY VolumesList; ///< List of active volumes
LIST_ENTRY PendingUnmountVolumesList; ///< List of volumes to unmount

} PARTLIST, *PPARTLIST;

Expand Down

0 comments on commit 7a228d3

Please sign in to comment.