summaryrefslogtreecommitdiffstats
path: root/FatPkg
diff options
context:
space:
mode:
authorHao Wu <hao.a.wu@intel.com>2018-04-14 11:06:13 +0800
committerHao Wu <hao.a.wu@intel.com>2018-04-18 15:08:14 +0800
commit255101471918ed8840f2be347916b90eef0e9c08 (patch)
tree2d7de144773b3c66e1fdfc00f2f232d7542c60f6 /FatPkg
parent104bbee55e1f90d8c7ae64d0d319c9dbfb24e06c (diff)
downloadedk2-255101471918ed8840f2be347916b90eef0e9c08.tar.gz
edk2-255101471918ed8840f2be347916b90eef0e9c08.tar.bz2
edk2-255101471918ed8840f2be347916b90eef0e9c08.zip
FatPkg/EnhancedFatDxe: Ensure traverse of subtasks is delete-safe
Within function FatQueueTask(), the traverse of FAT subtasks for executing the disk read/write is not delete-safe. For the below case: FatDiskIo(): When non-blocking access, creates subtasks and creates event (FatOnAccessComplete, NOTIFY level) when subtasks finish. FatQueueTask(): Traverses the subtasks and submits them one by one at Tpl lower than NOTIFY. Disk R/W completes really quick. FatOnAccessComplete(): Removes the finished subtask, causing the traverse in FatQueueTask() broken. This commits will refine the subtask traverse in FatQueueTask() to be delete-safe. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
Diffstat (limited to 'FatPkg')
-rw-r--r--FatPkg/EnhancedFatDxe/Misc.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/FatPkg/EnhancedFatDxe/Misc.c b/FatPkg/EnhancedFatDxe/Misc.c
index c035670bf7..af66b1d0e3 100644
--- a/FatPkg/EnhancedFatDxe/Misc.c
+++ b/FatPkg/EnhancedFatDxe/Misc.c
@@ -132,6 +132,7 @@ FatQueueTask (
{
EFI_STATUS Status;
LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
FAT_SUBTASK *Subtask;
//
@@ -149,9 +150,17 @@ FatQueueTask (
EfiReleaseLock (&FatTaskLock);
Status = EFI_SUCCESS;
- for ( Link = GetFirstNode (&Task->Subtasks)
- ; !IsNull (&Task->Subtasks, Link)
- ; Link = GetNextNode (&Task->Subtasks, Link)
+ //
+ // Use NextLink to store the next link of the list, because Link might be remove from the
+ // doubly-linked list and get freed in the end of current loop.
+ //
+ // Also, list operation APIs like IsNull() and GetNextNode() are avoided during the loop, since
+ // they may check the validity of doubly-linked lists by traversing them. These APIs cannot
+ // handle list elements being removed during the traverse.
+ //
+ for ( Link = GetFirstNode (&Task->Subtasks), NextLink = GetNextNode (&Task->Subtasks, Link)
+ ; Link != &Task->Subtasks
+ ; Link = NextLink, NextLink = Link->ForwardLink
) {
Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);
if (Subtask->Write) {