From patchwork Tue Jun 9 05:14:12 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Cernekee X-Patchwork-Id: 28269 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bilbo.ozlabs.org (Postfix) with ESMTPS id 2FDCEB70C0 for ; Tue, 9 Jun 2009 15:51:11 +1000 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1MDuBG-00064x-NC; Tue, 09 Jun 2009 05:47:30 +0000 Received: from [65.98.92.6] (helo=b32.net) by bombadil.infradead.org with esmtps (Exim 4.69 #1 (Red Hat Linux)) id 1MDuB6-00064k-UL for linux-mtd@lists.infradead.org; Tue, 09 Jun 2009 05:47:27 +0000 Received: (qmail 461 invoked from network); 9 Jun 2009 05:47:17 -0000 Received: from softdnserror (HELO two) (127.0.0.1) by softdnserror with SMTP; 9 Jun 2009 05:47:17 -0000 Received: by two (sSMTP sendmail emulation); Mon, 08 Jun 2009 22:46:37 -0700 From: Kevin Cernekee To: , Date: Mon, 8 Jun 2009 22:14:12 -0700 Subject: [PATCH] MTD: Add UBI reboot notifier Message-Id: <018abcd2d98090bda0f75d3c95c9ec85@localhost> X-Spam-Score: 0.1 (/) X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary: Content analysis details: (0.1 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.1 RDNS_NONE Delivered to trusted network by a host with no rDNS Cc: linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org ubifs_sync_fs() may queue up a new UBI erase transaction, which is processed in the background: bash# sync ubifs_sync_fs: enter schedule_erase: enter schedule_erase: exit ubi_sync: enter ubi_sync: exit ubifs_sync_fs: exit cfi_amdstd_erase_varsize: enter bash# cfi_amdstd_erase_varsize: exit Normally this is not a big deal. However, during the final sync before rebooting, it initiates an erase operation that is potentially still active when Linux restarts the machine: bash# reboot -f ubifs_sync_fs: enter schedule_erase: enter schedule_erase: exit ubi_sync: enter ubi_sync: exit ubifs_sync_fs: exit cfi_amdstd_erase_varsize: enter Restarting system. This is easiest to observe on a NOR flash. One factor is the long erase time. The other reason is because getting a NOR flash stuck in FL_ERASE mode will prevent the bootloader from running, unless the board provides a way for the processor to automatically reset the flash. In my experience, many boards do not. My proposal is to add a reboot notifier to let the UBI background thread terminate gracefully. The new ordering looks like this: bash# reboot -f ubifs_sync_fs: enter schedule_erase: enter schedule_erase: exit ubifs_sync_fs: exit cfi_amdstd_erase_varsize: enter ubi_reboot_notifier: enter cfi_amdstd_erase_varsize: exit ubi_reboot_notifier: exit cfi_amdstd_reboot: enter cfi_amdstd_reboot: exit cfi_amdstd_reboot doesn't really exist, but I added a dummy notifier to make sure that the ordering would be correct when using drivers that do have this feature. Signed-off-by: Kevin Cernekee --- drivers/mtd/ubi/build.c | 24 ++++++++++++++++++++++++ drivers/mtd/ubi/ubi.h | 2 ++ 2 files changed, 26 insertions(+), 0 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 4048db8..ca88059 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "ubi.h" /* Maximum length of the 'mtd=' parameter */ @@ -726,6 +727,23 @@ static int autoresize(struct ubi_device *ubi, int vol_id) } /** + * ubi_reboot_notifier - halt UBI transactions immediately prior to a reboot + * @n: notifier_block struct (inside our struct ubi_device) + * @val: unused + * @v: unused + */ +static int ubi_reboot_notifier(struct notifier_block *n, unsigned long val, + void *v) +{ + struct ubi_device *ubi = container_of(n, struct ubi_device, + reboot_notifier); + + if (ubi->bgt_thread) + kthread_stop(ubi->bgt_thread); + return NOTIFY_DONE; +} + +/** * ubi_attach_mtd_dev - attach an MTD device. * @mtd: MTD device description object * @ubi_num: number to assign to the new UBI device @@ -876,6 +894,11 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi->thread_enabled = 1; wake_up_process(ubi->bgt_thread); + /* Flash device priority is 0. UBI needs to shut down first. */ + ubi->reboot_notifier.priority = 1; + ubi->reboot_notifier.notifier_call = ubi_reboot_notifier; + register_reboot_notifier(&ubi->reboot_notifier); + ubi_devices[ubi_num] = ubi; return ubi_num; @@ -945,6 +968,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) * Before freeing anything, we have to stop the background thread to * prevent it from doing anything on this device while we are freeing. */ + unregister_reboot_notifier(&ubi->reboot_notifier); if (ubi->bgt_thread) kthread_stop(ubi->bgt_thread); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index c055511..44a45b9 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -420,6 +421,7 @@ struct ubi_device { struct task_struct *bgt_thread; int thread_enabled; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; + struct notifier_block reboot_notifier; /* I/O sub-system's stuff */ long long flash_size;