Patch "ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     ubi-ubi_wl_put_peb-fix-infinite-loop-when-wear-level.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit cf459d653dfb4e6be5f3394bf9d6b4aa445067e5
Author: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
Date:   Mon Jun 13 14:59:04 2022 +0800

    ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed
    
    [ Upstream commit 4d57a7333e26040f2b583983e1970d9d460e56b0 ]
    
    Following process will trigger an infinite loop in ubi_wl_put_peb():
    
            ubifs_bgt               ubi_bgt
    ubifs_leb_unmap
      ubi_leb_unmap
        ubi_eba_unmap_leb
          ubi_wl_put_peb    wear_leveling_worker
                              e1 = rb_entry(rb_first(&ubi->used)
                              e2 = get_peb_for_wl(ubi)
                              ubi_io_read_vid_hdr  // return err (flash fault)
                              out_error:
                                ubi->move_from = ubi->move_to = NULL
                                wl_entry_destroy(ubi, e1)
                                  ubi->lookuptbl[e->pnum] = NULL
          retry:
            e = ubi->lookuptbl[pnum];       // return NULL
            if (e == ubi->move_from) {      // NULL == NULL gets true
              goto retry;                   // infinite loop !!!
    
    $ top
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     COMMAND
      7676 root     20   0       0      0      0 R 100.0  0.0  ubifs_bgt0_0
    
    Fix it by:
     1) Letting ubi_wl_put_peb() returns directly if wearl leveling entry has
        been removed from 'ubi->lookuptbl'.
     2) Using 'ubi->wl_lock' protecting wl entry deletion to preventing an
        use-after-free problem for wl entry in ubi_wl_put_peb().
    
    Fetch a reproducer in [Link].
    
    Fixes: 43f9b25a9cdd7b1 ("UBI: bugfix: protect from volume removal")
    Fixes: ee59ba8b064f692 ("UBI: Fix stale pointers in ubi->lookuptbl")
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=216111
    Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
    Signed-off-by: Richard Weinberger <richard@xxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 4a672e925d869..2ee0e60c43c2e 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -972,11 +972,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
 	spin_lock(&ubi->wl_lock);
 	ubi->move_from = ubi->move_to = NULL;
 	ubi->move_to_put = ubi->wl_scheduled = 0;
+	wl_entry_destroy(ubi, e1);
+	wl_entry_destroy(ubi, e2);
 	spin_unlock(&ubi->wl_lock);
 
 	ubi_free_vid_buf(vidb);
-	wl_entry_destroy(ubi, e1);
-	wl_entry_destroy(ubi, e2);
 
 out_ro:
 	ubi_ro_mode(ubi);
@@ -1250,6 +1250,18 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
 retry:
 	spin_lock(&ubi->wl_lock);
 	e = ubi->lookuptbl[pnum];
+	if (!e) {
+		/*
+		 * This wl entry has been removed for some errors by other
+		 * process (eg. wear leveling worker), corresponding process
+		 * (except __erase_worker, which cannot concurrent with
+		 * ubi_wl_put_peb) will set ubi ro_mode at the same time,
+		 * just ignore this wl entry.
+		 */
+		spin_unlock(&ubi->wl_lock);
+		up_read(&ubi->fm_protect);
+		return 0;
+	}
 	if (e == ubi->move_from) {
 		/*
 		 * User is putting the physical eraseblock which was selected to



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux