lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID:
 <ME0P300MB07806E7C0A351C163E1176B3C93FA@ME0P300MB0780.AUSP300.PROD.OUTLOOK.COM>
Date: Sun, 24 Aug 2025 12:40:17 +0800
From: Yihe Jiang <he29@...mail.com>
To: David Woodhouse <dwmw2@...radead.org>,
	Richard Weinberger <richard@....at>
Cc: Yihe Jiang <he29@...mail.com>,
	linux-mtd@...ts.infradead.org,
	linux-kernel@...r.kernel.org
Subject: [PATCH] jffs2: add erase_on_mount mount option

On some slow MTD devices, mounting a newly-created empty filesystem
can cause the system to become extremely slow, as all empty blocks
are erased in the background after the first mount. This can preempt
userspace operations and affect filesystem performance.

This commit adds an erase_on_mount mount option. When specified with
rw, all pending blocks are erased during the mount process, avoiding
the speed drop after mounting. The option does not take effect when
mounting read-only.

Signed-off-by: Yihe Jiang <he29@...mail.com>
---
 fs/jffs2/fs.c          | 14 ++++++++++++++
 fs/jffs2/jffs2_fs_sb.h |  1 +
 fs/jffs2/super.c       | 10 ++++++++++
 3 files changed, 25 insertions(+)

diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index d175cccb7c55..65cbb47d73c4 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -411,6 +411,13 @@ int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc)
 		mutex_unlock(&c->alloc_sem);
 	}
 
+	if (!(fc->sb_flags & SB_RDONLY) && c->mount_opts.erase_on_mount) {
+		pr_info("erase_on_mount option set, erasing all pending blocks\n");
+		while (!list_empty(&c->erase_complete_list) ||
+		!list_empty(&c->erase_pending_list))
+			jffs2_erase_pending_blocks(c, 1);
+	}
+
 	if (!(fc->sb_flags & SB_RDONLY))
 		jffs2_start_garbage_collect_thread(c);
 
@@ -595,6 +602,13 @@ int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc)
 	sb->s_time_min = 0;
 	sb->s_time_max = U32_MAX;
 
+	if (!sb_rdonly(sb) && c->mount_opts.erase_on_mount) {
+		pr_info("erase_on_mount option set, erasing all pending blocks\n");
+		while (!list_empty(&c->erase_complete_list) ||
+		!list_empty(&c->erase_pending_list))
+			jffs2_erase_pending_blocks(c, 1);
+	}
+
 	if (!sb_rdonly(sb))
 		jffs2_start_garbage_collect_thread(c);
 	return 0;
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index 5a7091746f68..eb43416997f0 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -40,6 +40,7 @@ struct jffs2_mount_opts {
 	 * available space is less then 'rp_size'. */
 	bool set_rp_size;
 	unsigned int rp_size;
+	bool erase_on_mount;
 };
 
 /* A struct for the overall file system control.  Pointers to
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 4545f885c41e..270d24b336cd 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -91,6 +91,8 @@ static int jffs2_show_options(struct seq_file *s, struct dentry *root)
 		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
 	if (opts->set_rp_size)
 		seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
+	if (opts->erase_on_mount)
+		seq_puts(s, ",erase_on_mount");
 
 	return 0;
 }
@@ -167,6 +169,7 @@ static const struct export_operations jffs2_export_ops = {
 enum {
 	Opt_override_compr,
 	Opt_rp_size,
+	Opt_erase_on_mount,
 };
 
 static const struct constant_table jffs2_param_compr[] = {
@@ -183,6 +186,7 @@ static const struct constant_table jffs2_param_compr[] = {
 static const struct fs_parameter_spec jffs2_fs_parameters[] = {
 	fsparam_enum	("compr",	Opt_override_compr, jffs2_param_compr),
 	fsparam_u32	("rp_size",	Opt_rp_size),
+	fsparam_flag	("erase_on_mount",	Opt_erase_on_mount),
 	{}
 };
 
@@ -207,6 +211,9 @@ static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		c->mount_opts.rp_size = result.uint_32 * 1024;
 		c->mount_opts.set_rp_size = true;
 		break;
+	case Opt_erase_on_mount:
+		c->mount_opts.erase_on_mount = true;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -228,6 +235,9 @@ static inline void jffs2_update_mount_opts(struct fs_context *fc)
 		c->mount_opts.set_rp_size = new_c->mount_opts.set_rp_size;
 		c->mount_opts.rp_size = new_c->mount_opts.rp_size;
 	}
+
+	c->mount_opts.erase_on_mount = new_c->mount_opts.erase_on_mount;
+
 	mutex_unlock(&c->alloc_sem);
 }
 
-- 
2.50.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ