mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-29 08:34:07 +02:00
AtaBusDxe: Fix ReadBlockEx andWriteBlockEx to still signal event when the BufferSize is 0.
DiskIoDxe: Fix ReadDiskEx and WriteDiskEx to not modify the user’s buffer when the BufferSize is 0. DiskIoDxe: Fix ReadDiskEx and WriteDiskEx hang issue when the submitted blockio2 task is completed before submitting another blockio2 task. DiskIoDxe: Fix FlushEx to free the flush task item in callback (memory leak issue). Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16215 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
4202afa45d
commit
bf5a9493fa
@ -4,7 +4,7 @@
|
|||||||
This file implements protocol interfaces: Driver Binding protocol,
|
This file implements protocol interfaces: Driver Binding protocol,
|
||||||
Block IO protocol and DiskInfo protocol.
|
Block IO protocol and DiskInfo protocol.
|
||||||
|
|
||||||
Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
@ -1072,6 +1072,10 @@ BlockIoReadWrite (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (BufferSize == 0) {
|
if (BufferSize == 0) {
|
||||||
|
if ((Token != NULL) && (Token->Event != NULL)) {
|
||||||
|
Token->TransactionStatus = EFI_SUCCESS;
|
||||||
|
gBS->SignalEvent (Token->Event);
|
||||||
|
}
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
Aligned - A read of N contiguous sectors.
|
Aligned - A read of N contiguous sectors.
|
||||||
OverRun - The last byte is not on a sector boundary.
|
OverRun - The last byte is not on a sector boundary.
|
||||||
|
|
||||||
Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
@ -366,7 +366,15 @@ DiskIoDestroySubtask (
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
LIST_ENTRY *Link;
|
LIST_ENTRY *Link;
|
||||||
|
|
||||||
|
if (Subtask->Task != NULL) {
|
||||||
|
EfiAcquireLock (&Subtask->Task->SubtasksLock);
|
||||||
|
}
|
||||||
Link = RemoveEntryList (&Subtask->Link);
|
Link = RemoveEntryList (&Subtask->Link);
|
||||||
|
if (Subtask->Task != NULL) {
|
||||||
|
EfiReleaseLock (&Subtask->Task->SubtasksLock);
|
||||||
|
}
|
||||||
|
|
||||||
if (!Subtask->Blocking) {
|
if (!Subtask->Blocking) {
|
||||||
if (Subtask->WorkingBuffer != NULL) {
|
if (Subtask->WorkingBuffer != NULL) {
|
||||||
FreeAlignedPages (
|
FreeAlignedPages (
|
||||||
@ -430,19 +438,11 @@ DiskIo2OnReadWriteComplete (
|
|||||||
gBS->SignalEvent (Task->Token->Event);
|
gBS->SignalEvent (Task->Token->Event);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Mark token to NULL
|
// Mark token to NULL indicating the Task is a dead task.
|
||||||
//
|
//
|
||||||
Task->Token = NULL;
|
Task->Token = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsListEmpty (&Task->Subtasks)) {
|
|
||||||
EfiAcquireLock (&Instance->TaskQueueLock);
|
|
||||||
RemoveEntryList (&Task->Link);
|
|
||||||
EfiReleaseLock (&Instance->TaskQueueLock);
|
|
||||||
|
|
||||||
FreePool (Task);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -752,6 +752,42 @@ DiskIo2Cancel (
|
|||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
|
||||||
|
|
||||||
|
@param Instance Pointer to the DISK_IO_PRIVATE_DATA.
|
||||||
|
|
||||||
|
@retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.
|
||||||
|
@retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.
|
||||||
|
**/
|
||||||
|
BOOLEAN
|
||||||
|
DiskIo2RemoveCompletedTask (
|
||||||
|
IN DISK_IO_PRIVATE_DATA *Instance
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BOOLEAN QueueEmpty;
|
||||||
|
LIST_ENTRY *Link;
|
||||||
|
DISK_IO2_TASK *Task;
|
||||||
|
|
||||||
|
QueueEmpty = TRUE;
|
||||||
|
|
||||||
|
EfiAcquireLock (&Instance->TaskQueueLock);
|
||||||
|
for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
|
||||||
|
Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
|
||||||
|
if (IsListEmpty (&Task->Subtasks)) {
|
||||||
|
Link = RemoveEntryList (&Task->Link);
|
||||||
|
ASSERT (Task->Token == NULL);
|
||||||
|
FreePool (Task);
|
||||||
|
} else {
|
||||||
|
Link = GetNextNode (&Instance->TaskQueue, Link);
|
||||||
|
QueueEmpty = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EfiReleaseLock (&Instance->TaskQueueLock);
|
||||||
|
|
||||||
|
return QueueEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Common routine to access the disk.
|
Common routine to access the disk.
|
||||||
|
|
||||||
@ -781,12 +817,13 @@ DiskIo2ReadWriteDisk (
|
|||||||
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
|
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
|
||||||
EFI_BLOCK_IO_MEDIA *Media;
|
EFI_BLOCK_IO_MEDIA *Media;
|
||||||
LIST_ENTRY *Link;
|
LIST_ENTRY *Link;
|
||||||
|
LIST_ENTRY *NextLink;
|
||||||
LIST_ENTRY Subtasks;
|
LIST_ENTRY Subtasks;
|
||||||
DISK_IO_SUBTASK *Subtask;
|
DISK_IO_SUBTASK *Subtask;
|
||||||
DISK_IO2_TASK *Task;
|
DISK_IO2_TASK *Task;
|
||||||
BOOLEAN TaskQueueEmpty;
|
|
||||||
EFI_TPL OldTpl;
|
EFI_TPL OldTpl;
|
||||||
BOOLEAN Blocking;
|
BOOLEAN Blocking;
|
||||||
|
BOOLEAN SubtaskBlocking;
|
||||||
LIST_ENTRY *SubtasksPtr;
|
LIST_ENTRY *SubtasksPtr;
|
||||||
|
|
||||||
Task = NULL;
|
Task = NULL;
|
||||||
@ -803,24 +840,21 @@ DiskIo2ReadWriteDisk (
|
|||||||
if (Write && Media->ReadOnly) {
|
if (Write && Media->ReadOnly) {
|
||||||
return EFI_WRITE_PROTECTED;
|
return EFI_WRITE_PROTECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Blocking) {
|
if (Blocking) {
|
||||||
//
|
//
|
||||||
// Wait till pending async task is completed.
|
// Wait till pending async task is completed.
|
||||||
//
|
//
|
||||||
do {
|
while (!DiskIo2RemoveCompletedTask (Instance));
|
||||||
EfiAcquireLock (&Instance->TaskQueueLock);
|
|
||||||
TaskQueueEmpty = IsListEmpty (&Instance->TaskQueue);
|
|
||||||
EfiReleaseLock (&Instance->TaskQueueLock);
|
|
||||||
} while (!TaskQueueEmpty);
|
|
||||||
|
|
||||||
SubtasksPtr = &Subtasks;
|
SubtasksPtr = &Subtasks;
|
||||||
} else {
|
} else {
|
||||||
|
DiskIo2RemoveCompletedTask (Instance);
|
||||||
Task = AllocatePool (sizeof (DISK_IO2_TASK));
|
Task = AllocatePool (sizeof (DISK_IO2_TASK));
|
||||||
if (Task == NULL) {
|
if (Task == NULL) {
|
||||||
return EFI_OUT_OF_RESOURCES;
|
return EFI_OUT_OF_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
EfiAcquireLock (&Instance->TaskQueueLock);
|
EfiAcquireLock (&Instance->TaskQueueLock);
|
||||||
InsertTailList (&Instance->TaskQueue, &Task->Link);
|
InsertTailList (&Instance->TaskQueue, &Task->Link);
|
||||||
EfiReleaseLock (&Instance->TaskQueueLock);
|
EfiReleaseLock (&Instance->TaskQueueLock);
|
||||||
@ -828,6 +862,7 @@ DiskIo2ReadWriteDisk (
|
|||||||
Task->Signature = DISK_IO2_TASK_SIGNATURE;
|
Task->Signature = DISK_IO2_TASK_SIGNATURE;
|
||||||
Task->Instance = Instance;
|
Task->Instance = Instance;
|
||||||
Task->Token = Token;
|
Task->Token = Token;
|
||||||
|
EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
|
||||||
|
|
||||||
SubtasksPtr = &Task->Subtasks;
|
SubtasksPtr = &Task->Subtasks;
|
||||||
}
|
}
|
||||||
@ -842,12 +877,15 @@ DiskIo2ReadWriteDisk (
|
|||||||
ASSERT (!IsListEmpty (SubtasksPtr));
|
ASSERT (!IsListEmpty (SubtasksPtr));
|
||||||
|
|
||||||
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
||||||
for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); Link = GetNextNode (SubtasksPtr, Link)) {
|
for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
|
||||||
Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
|
; !IsNull (SubtasksPtr, Link)
|
||||||
|
; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
|
||||||
|
) {
|
||||||
|
Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
|
||||||
|
Subtask->Task = Task;
|
||||||
|
SubtaskBlocking = Subtask->Blocking;
|
||||||
|
|
||||||
if (!Subtask->Blocking) {
|
ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
|
||||||
Subtask->Task = Task;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Subtask->Write) {
|
if (Subtask->Write) {
|
||||||
//
|
//
|
||||||
@ -860,12 +898,12 @@ DiskIo2ReadWriteDisk (
|
|||||||
CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
|
CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Subtask->Blocking) {
|
if (SubtaskBlocking) {
|
||||||
Status = BlockIo->WriteBlocks (
|
Status = BlockIo->WriteBlocks (
|
||||||
BlockIo,
|
BlockIo,
|
||||||
MediaId,
|
MediaId,
|
||||||
Subtask->Lba,
|
Subtask->Lba,
|
||||||
Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
|
(Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
|
||||||
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -874,7 +912,7 @@ DiskIo2ReadWriteDisk (
|
|||||||
MediaId,
|
MediaId,
|
||||||
Subtask->Lba,
|
Subtask->Lba,
|
||||||
&Subtask->BlockIo2Token,
|
&Subtask->BlockIo2Token,
|
||||||
Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
|
(Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
|
||||||
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -883,12 +921,12 @@ DiskIo2ReadWriteDisk (
|
|||||||
//
|
//
|
||||||
// Read
|
// Read
|
||||||
//
|
//
|
||||||
if (Subtask->Blocking) {
|
if (SubtaskBlocking) {
|
||||||
Status = BlockIo->ReadBlocks (
|
Status = BlockIo->ReadBlocks (
|
||||||
BlockIo,
|
BlockIo,
|
||||||
MediaId,
|
MediaId,
|
||||||
Subtask->Lba,
|
Subtask->Lba,
|
||||||
Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
|
(Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
|
||||||
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
||||||
);
|
);
|
||||||
if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
|
if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
|
||||||
@ -900,12 +938,20 @@ DiskIo2ReadWriteDisk (
|
|||||||
MediaId,
|
MediaId,
|
||||||
Subtask->Lba,
|
Subtask->Lba,
|
||||||
&Subtask->BlockIo2Token,
|
&Subtask->BlockIo2Token,
|
||||||
Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
|
(Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
|
||||||
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SubtaskBlocking || EFI_ERROR (Status)) {
|
||||||
|
//
|
||||||
|
// Make sure the subtask list only contains non-blocking subtasks.
|
||||||
|
// Remove failed non-blocking subtasks as well because the callback won't be called.
|
||||||
|
//
|
||||||
|
DiskIoDestroySubtask (Instance, Subtask);
|
||||||
|
}
|
||||||
|
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -918,28 +964,15 @@ DiskIo2ReadWriteDisk (
|
|||||||
// We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
|
// We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
|
||||||
//
|
//
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
while (!IsNull (SubtasksPtr, Link)) {
|
while (!IsNull (SubtasksPtr, NextLink)) {
|
||||||
Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
|
Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
|
||||||
Link = DiskIoDestroySubtask (Instance, Subtask);
|
NextLink = DiskIoDestroySubtask (Instance, Subtask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask.
|
// It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
|
||||||
//
|
// so the subtasks list might be empty at this point.
|
||||||
for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); ) {
|
|
||||||
Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
|
|
||||||
if (Subtask->Blocking) {
|
|
||||||
Link = DiskIoDestroySubtask (Instance, Subtask);
|
|
||||||
} else {
|
|
||||||
Link = GetNextNode (SubtasksPtr, Link);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// It's possible that the callback runs before raising TPL to NOTIFY,
|
|
||||||
// so the subtasks list only contains blocking subtask.
|
|
||||||
// Remove the Task after the blocking subtasks are removed in above.
|
|
||||||
//
|
//
|
||||||
if (!Blocking && IsListEmpty (SubtasksPtr)) {
|
if (!Blocking && IsListEmpty (SubtasksPtr)) {
|
||||||
EfiAcquireLock (&Instance->TaskQueueLock);
|
EfiAcquireLock (&Instance->TaskQueueLock);
|
||||||
@ -1063,6 +1096,8 @@ DiskIo2OnFlushComplete (
|
|||||||
ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
|
ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
|
||||||
Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
|
Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
|
||||||
gBS->SignalEvent (Task->Token->Event);
|
gBS->SignalEvent (Task->Token->Event);
|
||||||
|
|
||||||
|
FreePool (Task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +51,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
UINT32 Signature;
|
UINT32 Signature;
|
||||||
LIST_ENTRY Link; /// < link to other task
|
LIST_ENTRY Link; /// < link to other task
|
||||||
|
EFI_LOCK SubtasksLock;
|
||||||
LIST_ENTRY Subtasks; /// < header of subtasks
|
LIST_ENTRY Subtasks; /// < header of subtasks
|
||||||
EFI_DISK_IO2_TOKEN *Token;
|
EFI_DISK_IO2_TOKEN *Token;
|
||||||
DISK_IO_PRIVATE_DATA *Instance;
|
DISK_IO_PRIVATE_DATA *Instance;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user