mtd: mtdoops: panic caused mtdoops to call mtdoops_erase function immediately
authorRay Zhang <sgzhang@google.com>
Mon, 10 Oct 2022 04:55:49 +0000 (04:55 +0000)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Mon, 7 Nov 2022 16:08:00 +0000 (17:08 +0100)
The panic function disables the local interrupts, preemption, and all
other processors. When the invoked mtdoops needs to erase a used page,
calling schedule_work() to do it will not work. Instead, just call
mtdoops_erase function immediately.

Tested:
~# echo c > /proc/sysrq-trigger
[  171.654759] sysrq: Trigger a crash
[  171.658325] Kernel panic - not syncing: sysrq triggered crash
......
[  172.406423] mtdoops: not ready 34, 35 (erase immediately)
[  172.432285] mtdoops: ready 34, 35
[  172.435633] Rebooting in 10 seconds..

Signed-off-by: Ray Zhang <sgzhang@google.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20221010045549.2221965-4-sgzhang@google.com
drivers/mtd/mtdoops.c

index 0226b9e9ea8f4b4b446127c15d505aa9248cfa12..2f11585b5613eeb24c0a15bbbc7e4caea3ca22e5 100644 (file)
@@ -170,7 +170,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
        mtdoops_erase(cxt);
 }
 
-static void mtdoops_inc_counter(struct mtdoops_context *cxt)
+static void mtdoops_inc_counter(struct mtdoops_context *cxt, int panic)
 {
        cxt->nextpage++;
        if (cxt->nextpage >= cxt->oops_pages)
@@ -180,12 +180,20 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
                cxt->nextcount = 0;
 
        if (page_is_used(cxt, cxt->nextpage)) {
-               schedule_work(&cxt->work_erase);
-               return;
+               pr_debug("not ready %d, %d (erase %s)\n",
+                        cxt->nextpage, cxt->nextcount,
+                        panic ? "immediately" : "scheduled");
+               if (panic) {
+                       /* In case of panic, erase immediately */
+                       mtdoops_erase(cxt);
+               } else {
+                       /* Otherwise, schedule work to erase it "nicely" */
+                       schedule_work(&cxt->work_erase);
+               }
+       } else {
+               pr_debug("ready %d, %d (no erase)\n",
+                        cxt->nextpage, cxt->nextcount);
        }
-
-       pr_debug("ready %d, %d (no erase)\n",
-                cxt->nextpage, cxt->nextcount);
 }
 
 static void mtdoops_write(struct mtdoops_context *cxt, int panic)
@@ -221,7 +229,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
        mark_page_used(cxt, cxt->nextpage);
        memset(cxt->oops_buf, 0xff, record_size);
 
-       mtdoops_inc_counter(cxt);
+       mtdoops_inc_counter(cxt, panic);
 out:
        clear_bit(0, &cxt->oops_buf_busy);
 }
@@ -286,7 +294,7 @@ static void find_next_position(struct mtdoops_context *cxt)
                cxt->nextcount = maxcount;
        }
 
-       mtdoops_inc_counter(cxt);
+       mtdoops_inc_counter(cxt, 0);
 }
 
 static void mtdoops_do_dump(struct kmsg_dumper *dumper,