Received: by 2002:a05:6359:c8b:b0:c7:702f:21d4 with SMTP id go11csp833280rwb; Wed, 28 Sep 2022 09:37:53 -0700 (PDT) X-Google-Smtp-Source: AMsMyM7JhxnC/P0T4ZDgbaJhCx9foKwwqId35ETUspAKSM+pqRB5Bsf3o6009/pdTgWTkY3NXsZ3 X-Received: by 2002:a63:b59:0:b0:434:2374:6d12 with SMTP id a25-20020a630b59000000b0043423746d12mr30026860pgl.311.1664383073333; Wed, 28 Sep 2022 09:37:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1664383073; cv=none; d=google.com; s=arc-20160816; b=h+BMgNNHfcijsPUAs6+MAaLn/op5iS/4OPo48EWFBHmZRraA9vOEZrfppp7LTq/dgq Ydb5zuwEGHhV9ds5v4piKZC7XaC0XGH7HJEuK8XAxStg4Jur+ncdzqTyyvjVa5O7Qc0f YWPbUR7jKWZ04+wZiHmKMJAxlT8vyujn2cBTu2Zx48/s3vfW3wNGcbBUpNrHjOAFVfSl 5GLgYs1BwU2Tu6P+m5jzRHmw+ryhLZuMCmAPqCXjILYSURmQxlV2N+zO7ufEAvRblX5j 2JDKTGs/U+qhMxMQT7weNqZ4sxCA9JQj2FgLIHMbelb5xkLm7xoLIqlBrH9XB25TK3m2 poFQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=0Z197TpQHPrQXuEhwXtpFt5Vin1hVGrvDXXAA+tMbJM=; b=aEAUUsc+E7TULnoJfQKYR8A6BeSXLbQI9ma94EyoxtxOxtxIrP3t9M1SnpFzurxX/M gkMngwwHSIfty/MFcDWN9Iv8MgY7OiOku05BYps9kDbIpCKV8mUVeLhZX/1QGWmb3HAx I9eRo8W9Lrp9Waobgnki2fCrXEPDREo9CuDV5NOxTZ/PVTf+4ogqHoGjYJmhAFf2zDcE o0SSgiUaZJos8WNVkJm1jaV0xQ3FEDJ1izPf5nqMfAnoNLqg+WocMl6P3j+4NkAbMH5f IeZH/ms7RefKo/Z1JotHcG3yI+FW+h1HJez/9CkWpKiJkwYpDknU2kssgY0ZnB2/1zVX EeKg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=aaJsxom3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id o7-20020a6548c7000000b0041bdae7558esi5629663pgs.653.2022.09.28.09.37.42; Wed, 28 Sep 2022 09:37:53 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=aaJsxom3; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234288AbiI1QLM (ORCPT + 99 others); Wed, 28 Sep 2022 12:11:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55126 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233749AbiI1QLJ (ORCPT ); Wed, 28 Sep 2022 12:11:09 -0400 Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 82F326AE9B for ; Wed, 28 Sep 2022 09:11:05 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id BAC60CE1C78 for ; Wed, 28 Sep 2022 16:11:03 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4F64BC433D6; Wed, 28 Sep 2022 16:11:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1664381462; bh=hB+qPySOh7o6qLA/PbK/Q6XmksMD2SEhEx5giJmW3fw=; h=From:To:Cc:Subject:Date:From; b=aaJsxom3/mvEdyit3Q2dwfQkYWlDVh0TQt7PWz5GtHwBOTfhBUfiJTC2xVoO50DUp /Qct4qdll21rDHjQWirvKEb8qPNtL4PXiPHwEmYpFC+mUNzlXDPRYoZCWo/FGq2OAb wRPWreV0H06vR9ppml95R/leRG55d3NqOMlX8yd7XwE8KQx8oXF6PfQh5IGVOwy2n5 DLR8jgi2vRxQCnkHc/Q+cEJoRpW8X71Vzqccg2765hQnxojUgZlVi0vzH+48GpMn2J 0YDgiODzuyLp7AffofK0pd9SKWh89RI8+R6OYbdkLuDIPRc9peINun0qQPy+YZFh9n ST3EF9HcccmRw== From: Chao Yu To: jaegeuk@kernel.org Cc: linux-f2fs-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, Chao Yu Subject: [PATCH v2 3/3] f2fs: support errors=remount-ro|continue|panic mountoption Date: Thu, 29 Sep 2022 00:09:49 +0800 Message-Id: <20220928160949.5105-1-chao@kernel.org> X-Mailer: git-send-email 2.36.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.2 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch supports errors=remount-ro|continue|panic mount option. Signed-off-by: Chao Yu --- v2: - fix to load sb.s_stop_reason during fill_super(). Documentation/filesystems/f2fs.rst | 4 + fs/f2fs/checkpoint.c | 7 +- fs/f2fs/f2fs.h | 18 ++++- fs/f2fs/super.c | 115 ++++++++++++++++++++++++++++- 4 files changed, 133 insertions(+), 11 deletions(-) diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index d0c09663dae8..6aa14e03f337 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -341,6 +341,10 @@ memory=%s Control memory mode. This supports "normal" and "low" modes. Because of the nature of low memory devices, in this mode, f2fs will try to save memory sometimes by sacrificing performance. "normal" mode is the default mode and same as before. +errors=%s Specify f2fs behavior on critical errors. This supports modes: + "panic", "continue" and "remount-ro", respectively, triggers + panic immediately, continue without doing anything, or remount + the partition in read-only mode (default behavior). ======================== ============================================================ Debugfs Entries diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 0c82dae082aa..109e96c15b84 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -30,12 +30,9 @@ void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io, unsigned char reason) { f2fs_build_fault_attr(sbi, 0, 0); - set_ckpt_flags(sbi, CP_ERROR_FLAG); - if (!end_io) { + if (!end_io) f2fs_flush_merged_writes(sbi); - - f2fs_handle_stop(sbi, reason); - } + f2fs_handle_critical_error(sbi, reason, end_io); } /* diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 2ed00111a399..254f7f153477 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -160,6 +160,7 @@ struct f2fs_mount_info { int fs_mode; /* fs mode: LFS or ADAPTIVE */ int bggc_mode; /* bggc mode: off, on or sync */ int memory_mode; /* memory mode */ + int errors; /* errors parameter */ int discard_unit; /* * discard command's offset/size should * be aligned to this unit: block, @@ -1382,7 +1383,11 @@ enum { MEMORY_MODE_LOW, /* memory mode for low memry devices */ }; - +enum errors_option { + MOUNT_ERRORS_READONLY, /* remount fs ro on errors */ + MOUNT_ERRORS_CONTINUE, /* continue on errors */ + MOUNT_ERRORS_PANIC, /* panic on errors */ +}; static inline int f2fs_test_bit(unsigned int nr, char *addr); static inline void f2fs_set_bit(unsigned int nr, char *addr); @@ -1818,7 +1823,13 @@ struct f2fs_sb_info { struct workqueue_struct *post_read_wq; /* post read workqueue */ - unsigned char errors[MAX_F2FS_ERRORS]; /* error flags */ + /* + * If we are in irq context, let's update error information into + * on-disk superblock in the work. + */ + struct work_struct s_error_work; + unsigned char errors[MAX_F2FS_ERRORS]; /* error flags */ + unsigned char stop_reason[MAX_STOP_REASON]; /* stop reason */ spinlock_t error_lock; /* protect errors array */ bool error_dirty; /* errors of sb is dirty */ @@ -3563,7 +3574,8 @@ int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly); int f2fs_quota_sync(struct super_block *sb, int type); loff_t max_file_blocks(struct inode *inode); void f2fs_quota_off_umount(struct super_block *sb); -void f2fs_handle_stop(struct f2fs_sb_info *sbi, unsigned char reason); +void f2fs_handle_critical_error(struct f2fs_sb_info *sbi, unsigned char reason, + bool irq_context); void f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error); int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover); int f2fs_sync_fs(struct super_block *sb, int sync); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index ee0a5a17ba39..60bd0344f573 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -161,6 +161,7 @@ enum { Opt_nogc_merge, Opt_discard_unit, Opt_memory_mode, + Opt_errors, Opt_err, }; @@ -238,6 +239,7 @@ static match_table_t f2fs_tokens = { {Opt_nogc_merge, "nogc_merge"}, {Opt_discard_unit, "discard_unit=%s"}, {Opt_memory_mode, "memory=%s"}, + {Opt_errors, "errors=%s"}, {Opt_err, NULL}, }; @@ -1253,6 +1255,25 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) } kfree(name); break; + case Opt_errors: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + if (!strcmp(name, "remount-ro")) { + F2FS_OPTION(sbi).errors = + MOUNT_ERRORS_READONLY; + } else if (!strcmp(name, "continue")) { + F2FS_OPTION(sbi).errors = + MOUNT_ERRORS_CONTINUE; + } else if (!strcmp(name, "panic")) { + F2FS_OPTION(sbi).errors = + MOUNT_ERRORS_PANIC; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; default: f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value", p); @@ -2031,6 +2052,13 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) else if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW) seq_printf(seq, ",memory=%s", "low"); + if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_READONLY) + seq_printf(seq, ",errors=%s", "remount-ro"); + else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE) + seq_printf(seq, ",errors=%s", "continue"); + else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC) + seq_printf(seq, ",errors=%s", "panic"); + return 0; } @@ -2053,6 +2081,7 @@ static void default_options(struct f2fs_sb_info *sbi) F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS; F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON; F2FS_OPTION(sbi).memory_mode = MEMORY_MODE_NORMAL; + F2FS_OPTION(sbi).errors = MOUNT_ERRORS_READONLY; sbi->sb->s_flags &= ~SB_INLINECRYPT; @@ -3846,7 +3875,16 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) return err; } -void f2fs_handle_stop(struct f2fs_sb_info *sbi, unsigned char reason) +static void save_stop_reason(struct f2fs_sb_info *sbi, unsigned char reason) + +{ + spin_lock(&sbi->error_lock); + if (sbi->stop_reason[reason] < ((1 << BITS_PER_BYTE) - 1)) + sbi->stop_reason[reason]++; + spin_unlock(&sbi->error_lock); +} + +void f2fs_record_stop_reason(struct f2fs_sb_info *sbi, unsigned char reason) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); @@ -3854,8 +3892,9 @@ void f2fs_handle_stop(struct f2fs_sb_info *sbi, unsigned char reason) f2fs_down_write(&sbi->sb_lock); - if (raw_super->s_stop_reason[reason] < ((1 << BITS_PER_BYTE) - 1)) - raw_super->s_stop_reason[reason]++; + spin_lock(&sbi->error_lock); + memcpy(raw_super->s_stop_reason, sbi->stop_reason, MAX_STOP_REASON); + spin_unlock(&sbi->error_lock); err = f2fs_commit_super(sbi, false); if (err) @@ -3909,6 +3948,74 @@ void f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error) f2fs_up_write(&sbi->sb_lock); } +static bool system_going_down(void) +{ + return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF + || system_state == SYSTEM_RESTART; +} + +void f2fs_handle_critical_error(struct f2fs_sb_info *sbi, unsigned char reason, + bool irq_context) +{ + struct super_block *sb = sbi->sb; + bool force_ro = reason == STOP_CP_REASON_SHUTDOWN; + bool continue_fs = !force_ro && + F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE; + + if (!continue_fs && !sb_rdonly(sb)) + set_ckpt_flags(sbi, CP_ERROR_FLAG); + + if (!bdev_read_only(sb->s_bdev)) { + save_stop_reason(sbi, reason); + + if (irq_context) + schedule_work(&sbi->s_error_work); + else + f2fs_record_stop_reason(sbi, reason); + } + + /* + * We force ERRORS_RO behavior when system is rebooting. Otherwise we + * could panic during 'reboot -f' as the underlying device got already + * disabled. + */ + if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC && + !force_ro && !system_going_down()) + panic("F2FS-fs (device %s): panic forced after error\n", + sb->s_id); + + /* continue filesystem operators if errors=continue */ + if (continue_fs || sb_rdonly(sb)) + return; + + f2fs_warn(sbi, "Remounting filesystem read-only"); + /* + * Make sure updated value of ->s_mount_flags will be visible before + * ->s_flags update + */ + smp_wmb(); + sb->s_flags |= SB_RDONLY; + + f2fs_stop_gc_thread(sbi); + f2fs_stop_discard_thread(sbi); +} + +static void flush_error_work(struct work_struct *work) +{ + struct f2fs_sb_info *sbi = container_of(work, + struct f2fs_sb_info, s_error_work); + int ret; + + if (sb_rdonly(sbi->sb)) + return; + + f2fs_down_write(&sbi->sb_lock); + ret = f2fs_commit_super(sbi, false); + f2fs_up_write(&sbi->sb_lock); + if (ret) + f2fs_err(sbi, "flush_error_work() fails to commit superblock ret:%d", ret); +} + static int f2fs_scan_devices(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); @@ -4256,8 +4363,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_devices; } + INIT_WORK(&sbi->s_error_work, flush_error_work); spin_lock_init(&sbi->error_lock); memcpy(sbi->errors, raw_super->s_errors, MAX_F2FS_ERRORS); + memcpy(sbi->stop_reason, raw_super->s_stop_reason, MAX_STOP_REASON); sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count); -- 2.36.1