From bf5a9493fa9d7013015ac511714d4efdca23ae34 Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 15 Oct 2014 04:49:04 +0000 Subject: [PATCH] =?utf8?q?AtaBusDxe:=20Fix=20ReadBlockEx=20andWriteBlockEx?= =?utf8?q?=20to=20still=20signal=20event=20when=20the=20BufferSize=20is=20?= =?utf8?q?0.=20DiskIoDxe:=20Fix=20ReadDiskEx=20and=20WriteDiskEx=20to=20no?= =?utf8?q?t=20modify=20the=20user=E2=80=99s=20buffer=20when=20the=20Buffer?= =?utf8?q?Size=20is=200.=20DiskIoDxe:=20Fix=20ReadDiskEx=20and=20WriteDisk?= =?utf8?q?Ex=20hang=20issue=20when=20the=20submitted=20blockio2=20task=20i?= =?utf8?q?s=20completed=20before=20submitting=20another=20blockio2=20task.?= =?utf8?q?=20DiskIoDxe:=20Fix=20FlushEx=20to=20free=20the=20flush=20task?= =?utf8?q?=20item=20in=20callback=20(memory=20leak=20issue).?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Feng Tian git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16215 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c | 6 +- .../Universal/Disk/DiskIoDxe/DiskIo.c | 131 +++++++++++------- .../Universal/Disk/DiskIoDxe/DiskIo.h | 1 + 3 files changed, 89 insertions(+), 49 deletions(-) diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c index b113b8d851..26783169ea 100644 --- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c @@ -4,7 +4,7 @@ This file implements protocol interfaces: Driver Binding protocol, Block IO protocol and DiskInfo protocol. - Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials 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 @@ -1072,6 +1072,10 @@ BlockIoReadWrite ( } if (BufferSize == 0) { + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + gBS->SignalEvent (Token->Event); + } return EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c index 0658299288..0f0dbfee82 100644 --- a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c +++ b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c @@ -9,7 +9,7 @@ Aligned - A read of N contiguous sectors. OverRun - The last byte is not on a sector boundary. -Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials 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 @@ -366,7 +366,15 @@ DiskIoDestroySubtask ( ) { LIST_ENTRY *Link; + + if (Subtask->Task != NULL) { + EfiAcquireLock (&Subtask->Task->SubtasksLock); + } Link = RemoveEntryList (&Subtask->Link); + if (Subtask->Task != NULL) { + EfiReleaseLock (&Subtask->Task->SubtasksLock); + } + if (!Subtask->Blocking) { if (Subtask->WorkingBuffer != NULL) { FreeAlignedPages ( @@ -430,19 +438,11 @@ DiskIo2OnReadWriteComplete ( gBS->SignalEvent (Task->Token->Event); // - // Mark token to NULL + // Mark token to NULL indicating the Task is a dead task. // 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; } +/** + 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. @@ -781,12 +817,13 @@ DiskIo2ReadWriteDisk ( EFI_BLOCK_IO2_PROTOCOL *BlockIo2; EFI_BLOCK_IO_MEDIA *Media; LIST_ENTRY *Link; + LIST_ENTRY *NextLink; LIST_ENTRY Subtasks; DISK_IO_SUBTASK *Subtask; DISK_IO2_TASK *Task; - BOOLEAN TaskQueueEmpty; EFI_TPL OldTpl; BOOLEAN Blocking; + BOOLEAN SubtaskBlocking; LIST_ENTRY *SubtasksPtr; Task = NULL; @@ -803,24 +840,21 @@ DiskIo2ReadWriteDisk ( if (Write && Media->ReadOnly) { return EFI_WRITE_PROTECTED; } - + if (Blocking) { // // Wait till pending async task is completed. // - do { - EfiAcquireLock (&Instance->TaskQueueLock); - TaskQueueEmpty = IsListEmpty (&Instance->TaskQueue); - EfiReleaseLock (&Instance->TaskQueueLock); - } while (!TaskQueueEmpty); + while (!DiskIo2RemoveCompletedTask (Instance)); SubtasksPtr = &Subtasks; } else { + DiskIo2RemoveCompletedTask (Instance); Task = AllocatePool (sizeof (DISK_IO2_TASK)); if (Task == NULL) { return EFI_OUT_OF_RESOURCES; } - + EfiAcquireLock (&Instance->TaskQueueLock); InsertTailList (&Instance->TaskQueue, &Task->Link); EfiReleaseLock (&Instance->TaskQueueLock); @@ -828,6 +862,7 @@ DiskIo2ReadWriteDisk ( Task->Signature = DISK_IO2_TASK_SIGNATURE; Task->Instance = Instance; Task->Token = Token; + EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY); SubtasksPtr = &Task->Subtasks; } @@ -842,12 +877,15 @@ DiskIo2ReadWriteDisk ( ASSERT (!IsListEmpty (SubtasksPtr)); OldTpl = gBS->RaiseTPL (TPL_CALLBACK); - for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); Link = GetNextNode (SubtasksPtr, Link)) { - Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE); + for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link) + ; !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) { - Subtask->Task = Task; - } + ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize)); if (Subtask->Write) { // @@ -860,12 +898,12 @@ DiskIo2ReadWriteDisk ( CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length); } - if (Subtask->Blocking) { + if (SubtaskBlocking) { Status = BlockIo->WriteBlocks ( BlockIo, MediaId, 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 ); } else { @@ -874,7 +912,7 @@ DiskIo2ReadWriteDisk ( MediaId, Subtask->Lba, &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 ); } @@ -883,12 +921,12 @@ DiskIo2ReadWriteDisk ( // // Read // - if (Subtask->Blocking) { + if (SubtaskBlocking) { Status = BlockIo->ReadBlocks ( BlockIo, MediaId, 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 ); if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) { @@ -900,12 +938,20 @@ DiskIo2ReadWriteDisk ( MediaId, Subtask->Lba, &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 ); } } - + + 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)) { 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. // if (EFI_ERROR (Status)) { - while (!IsNull (SubtasksPtr, Link)) { - Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE); - Link = DiskIoDestroySubtask (Instance, Subtask); + while (!IsNull (SubtasksPtr, NextLink)) { + Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE); + NextLink = DiskIoDestroySubtask (Instance, Subtask); } } // - // Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask. - // - 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. + // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY, + // so the subtasks list might be empty at this point. // if (!Blocking && IsListEmpty (SubtasksPtr)) { EfiAcquireLock (&Instance->TaskQueueLock); @@ -1063,6 +1096,8 @@ DiskIo2OnFlushComplete ( ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE); Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus; gBS->SignalEvent (Task->Token->Event); + + FreePool (Task); } /** diff --git a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h index 5e89684f66..7591e469a1 100644 --- a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h +++ b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h @@ -51,6 +51,7 @@ typedef struct { typedef struct { UINT32 Signature; LIST_ENTRY Link; /// < link to other task + EFI_LOCK SubtasksLock; LIST_ENTRY Subtasks; /// < header of subtasks EFI_DISK_IO2_TOKEN *Token; DISK_IO_PRIVATE_DATA *Instance; -- 2.39.2