[edk2] [PATCH] FatPkg/EnhancedFatDxe: Ensure traverse of subtasks is delete-safe

Hao Wu posted 1 patch 6 years ago
Failed in applying to current master (apply log)
FatPkg/EnhancedFatDxe/Misc.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
[edk2] [PATCH] FatPkg/EnhancedFatDxe: Ensure traverse of subtasks is delete-safe
Posted by Hao Wu 6 years ago
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.

Cc: Ruiyu Ni <ruiyu.ni@intel.com>
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>
---
 FatPkg/EnhancedFatDxe/Misc.c | 15 ++++++++++++---
 1 file 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) {
-- 
2.12.0.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel