All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ext4: Add periodic superblock update check
@ 2023-07-31 12:25 Vitaliy Kuznetsov
  2023-08-02 21:18 ` Andreas Dilger
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Vitaliy Kuznetsov @ 2023-07-31 12:25 UTC (permalink / raw)
  To: linux-ext4, adilger; +Cc: Vitaliy Kuznetsov

This patch introduces a mechanism to periodically check and update
the superblock within the ext4 file system. The main purpose of this
patch is to keep the disk superblock up to date. The update will be
performed if more than one hour has passed since the last update, and
if more than 16MB of data have been written to disk.

This check and update is performed within the ext4_journal_commit_callback
function, ensuring that the superblock is written while the disk is
active, rather than based on a timer that may trigger during disk idle
periods.

Discussion https://www.spinics.net/lists/linux-ext4/msg85865.html

Signed-off-by: Vitaliy Kuznetsov <vk.en.mail@gmail.com>
---
 fs/ext4/super.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/sysfs.c |  4 ++--
 2 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c94ebf704616..2159e9705404 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -433,6 +433,57 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi)
 #define ext4_get_tstamp(es, tstamp) \
 	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)

+#define EXT4_SB_REFRESH_INTERVAL_SEC (3600) /* seconds (1 hour) */
+#define EXT4_SB_REFRESH_INTERVAL_KB (16384) /* kilobytes (16MB) */
+
+/*
+ * The ext4_maybe_update_superblock() function checks and updates the
+ * superblock if needed.
+ *
+ * This function is designed to update the on-disk superblock only under
+ * certain conditions to prevent excessive disk writes and unnecessary
+ * waking of the disk from sleep. The superblock will be updated if:
+ * 1. More than an hour has passed since the last superblock update, and
+ * 2. More than 16MB have been written since the last superblock update.
+ *
+ * @sb: The superblock
+ */
+static void ext4_maybe_update_superblock(struct super_block *sb)
+{
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct ext4_super_block *es = sbi->s_es;
+	journal_t *journal = sbi->s_journal;
+	time64_t now;
+	__u64 last_update;
+	__u64 lifetime_write_kbytes;
+	__u64 diff_size;
+
+	if (sb_rdonly(sb) || !(sb->s_flags & SB_ACTIVE) ||
+	    !journal || (journal->j_flags & JBD2_UNMOUNT))
+		return;
+
+	now = ktime_get_real_seconds();
+	last_update = ext4_get_tstamp(es, s_wtime);
+
+	if (likely(now - last_update < EXT4_SB_REFRESH_INTERVAL_SEC))
+		return;
+
+	lifetime_write_kbytes = sbi->s_kbytes_written +
+		((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
+		  sbi->s_sectors_written_start) >> 1);
+
+	/* Get the number of kilobytes not written to disk to account
+	 * for statistics and compare with a multiple of 16 MB. This
+	 * is used to determine when the next superblock commit should
+	 * occur (i.e. not more often than once per 16MB if there was
+	 * less written in an hour).
+	 */
+	diff_size = lifetime_write_kbytes - le64_to_cpu(es->s_kbytes_written);
+
+	if (diff_size > EXT4_SB_REFRESH_INTERVAL_KB)
+		schedule_work(&EXT4_SB(sb)->s_error_work);
+}
+
 /*
  * The del_gendisk() function uninitializes the disk-specific data
  * structures, including the bdi structure, without telling anyone
@@ -459,6 +510,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
 	BUG_ON(txn->t_state == T_FINISHED);

 	ext4_process_freed_data(sb, txn->t_tid);
+	ext4_maybe_update_superblock(sb);

 	spin_lock(&sbi->s_md_lock);
 	while (!list_empty(&txn->t_private_list)) {
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
index 6d332dff79dd..9f334de4f636 100644
--- a/fs/ext4/sysfs.c
+++ b/fs/ext4/sysfs.c
@@ -515,7 +515,8 @@ static const struct kobj_type ext4_feat_ktype = {

 void ext4_notify_error_sysfs(struct ext4_sb_info *sbi)
 {
-	sysfs_notify(&sbi->s_kobj, NULL, "errors_count");
+	if (sbi->s_add_error_count > 0)
+		sysfs_notify(&sbi->s_kobj, NULL, "errors_count");
 }

 static struct kobject *ext4_root;
@@ -605,4 +606,3 @@ void ext4_exit_sysfs(void)
 	remove_proc_entry(proc_dirname, NULL);
 	ext4_proc_root = NULL;
 }
-
--

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] ext4: Add periodic superblock update check
  2023-07-31 12:25 [PATCH] ext4: Add periodic superblock update check Vitaliy Kuznetsov
@ 2023-08-02 21:18 ` Andreas Dilger
  2023-08-04 20:58 ` Theodore Ts'o
  2023-08-10 14:38 ` [PATCH v2] " Vitaliy Kuznetsov
  2 siblings, 0 replies; 8+ messages in thread
From: Andreas Dilger @ 2023-08-02 21:18 UTC (permalink / raw)
  To: Vitaliy Kuznetsov; +Cc: linux-ext4

[-- Attachment #1: Type: text/plain, Size: 4453 bytes --]

On Jul 31, 2023, at 6:25 AM, Vitaliy Kuznetsov <vk.en.mail@gmail.com> wrote:
> 
> This patch introduces a mechanism to periodically check and update
> the superblock within the ext4 file system. The main purpose of this
> patch is to keep the disk superblock up to date. The update will be
> performed if more than one hour has passed since the last update, and
> if more than 16MB of data have been written to disk.
> 
> This check and update is performed within the ext4_journal_commit_callback
> function, ensuring that the superblock is written while the disk is
> active, rather than based on a timer that may trigger during disk idle
> periods.
> 
> Discussion https://www.spinics.net/lists/linux-ext4/msg85865.html
> 
> Signed-off-by: Vitaliy Kuznetsov <vk.en.mail@gmail.com>

Thanks for sending the patch.

Reviewed-by: Andreas Dilger <adilger@dilger.ca>

> ---
> fs/ext4/super.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
> fs/ext4/sysfs.c |  4 ++--
> 2 files changed, 54 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index c94ebf704616..2159e9705404 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -433,6 +433,57 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi)
> #define ext4_get_tstamp(es, tstamp) \
> 	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)
> 
> +#define EXT4_SB_REFRESH_INTERVAL_SEC (3600) /* seconds (1 hour) */
> +#define EXT4_SB_REFRESH_INTERVAL_KB (16384) /* kilobytes (16MB) */
> +
> +/*
> + * The ext4_maybe_update_superblock() function checks and updates the
> + * superblock if needed.
> + *
> + * This function is designed to update the on-disk superblock only under
> + * certain conditions to prevent excessive disk writes and unnecessary
> + * waking of the disk from sleep. The superblock will be updated if:
> + * 1. More than an hour has passed since the last superblock update, and
> + * 2. More than 16MB have been written since the last superblock update.
> + *
> + * @sb: The superblock
> + */
> +static void ext4_maybe_update_superblock(struct super_block *sb)
> +{
> +	struct ext4_sb_info *sbi = EXT4_SB(sb);
> +	struct ext4_super_block *es = sbi->s_es;
> +	journal_t *journal = sbi->s_journal;
> +	time64_t now;
> +	__u64 last_update;
> +	__u64 lifetime_write_kbytes;
> +	__u64 diff_size;
> +
> +	if (sb_rdonly(sb) || !(sb->s_flags & SB_ACTIVE) ||
> +	    !journal || (journal->j_flags & JBD2_UNMOUNT))
> +		return;
> +
> +	now = ktime_get_real_seconds();
> +	last_update = ext4_get_tstamp(es, s_wtime);
> +
> +	if (likely(now - last_update < EXT4_SB_REFRESH_INTERVAL_SEC))
> +		return;
> +
> +	lifetime_write_kbytes = sbi->s_kbytes_written +
> +		((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
> +		  sbi->s_sectors_written_start) >> 1);
> +
> +	/* Get the number of kilobytes not written to disk to account
> +	 * for statistics and compare with a multiple of 16 MB. This
> +	 * is used to determine when the next superblock commit should
> +	 * occur (i.e. not more often than once per 16MB if there was
> +	 * less written in an hour).
> +	 */
> +	diff_size = lifetime_write_kbytes - le64_to_cpu(es->s_kbytes_written);
> +
> +	if (diff_size > EXT4_SB_REFRESH_INTERVAL_KB)
> +		schedule_work(&EXT4_SB(sb)->s_error_work);
> +}
> +
> /*
>  * The del_gendisk() function uninitializes the disk-specific data
>  * structures, including the bdi structure, without telling anyone
> @@ -459,6 +510,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
> 	BUG_ON(txn->t_state == T_FINISHED);
> 
> 	ext4_process_freed_data(sb, txn->t_tid);
> +	ext4_maybe_update_superblock(sb);
> 
> 	spin_lock(&sbi->s_md_lock);
> 	while (!list_empty(&txn->t_private_list)) {
> diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
> index 6d332dff79dd..9f334de4f636 100644
> --- a/fs/ext4/sysfs.c
> +++ b/fs/ext4/sysfs.c
> @@ -515,7 +515,8 @@ static const struct kobj_type ext4_feat_ktype = {
> 
> void ext4_notify_error_sysfs(struct ext4_sb_info *sbi)
> {
> -	sysfs_notify(&sbi->s_kobj, NULL, "errors_count");
> +	if (sbi->s_add_error_count > 0)
> +		sysfs_notify(&sbi->s_kobj, NULL, "errors_count");
> }
> 
> static struct kobject *ext4_root;
> @@ -605,4 +606,3 @@ void ext4_exit_sysfs(void)
> 	remove_proc_entry(proc_dirname, NULL);
> 	ext4_proc_root = NULL;
> }
> -
> --


Cheers, Andreas






[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 873 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] ext4: Add periodic superblock update check
  2023-07-31 12:25 [PATCH] ext4: Add periodic superblock update check Vitaliy Kuznetsov
  2023-08-02 21:18 ` Andreas Dilger
@ 2023-08-04 20:58 ` Theodore Ts'o
  2023-08-10 14:38 ` [PATCH v2] " Vitaliy Kuznetsov
  2 siblings, 0 replies; 8+ messages in thread
From: Theodore Ts'o @ 2023-08-04 20:58 UTC (permalink / raw)
  To: Vitaliy Kuznetsov; +Cc: linux-ext4, adilger

On Mon, Jul 31, 2023 at 04:25:26PM +0400, Vitaliy Kuznetsov wrote:
> diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
> index 6d332dff79dd..9f334de4f636 100644
> --- a/fs/ext4/sysfs.c
> +++ b/fs/ext4/sysfs.c
> @@ -515,7 +515,8 @@ static const struct kobj_type ext4_feat_ktype = {
> 
>  void ext4_notify_error_sysfs(struct ext4_sb_info *sbi)
>  {
> -	sysfs_notify(&sbi->s_kobj, NULL, "errors_count");
> +	if (sbi->s_add_error_count > 0)
> +		sysfs_notify(&sbi->s_kobj, NULL, "errors_count");
>  }

The problem is that ext4_notify_error_sysfs() is called in
flush_stashed_error_work() **after** that function calls
ext4_update_super() --- and ext4_update_super will zero out
s_add_error_count.  So this will result in the sysfs_notify call
*never* getting called, which would be a regression.  So
unfortunately, I can't accept this patch as currently written.

Fortunately, only flush_stashed_error_work() calls
ext4_notify_error_sysfs(), so it should be easy enough to sample
s_add_error_count before calling ext4_update_super(), and then
conditionally call sysfs_notify() if it is non-zero.

	      	   		     	   - Ted

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2] ext4: Add periodic superblock update check
  2023-07-31 12:25 [PATCH] ext4: Add periodic superblock update check Vitaliy Kuznetsov
  2023-08-02 21:18 ` Andreas Dilger
  2023-08-04 20:58 ` Theodore Ts'o
@ 2023-08-10 14:38 ` Vitaliy Kuznetsov
  2023-08-24  4:53   ` Theodore Ts'o
  2 siblings, 1 reply; 8+ messages in thread
From: Vitaliy Kuznetsov @ 2023-08-10 14:38 UTC (permalink / raw)
  To: linux-ext4, tytso; +Cc: adilger, Vitaliy Kuznetsov

This patch introduces a mechanism to periodically check and update
the superblock within the ext4 file system. The main purpose of this
patch is to keep the disk superblock up to date. The update will be
performed if more than one hour has passed since the last update, and
if more than 16MB of data have been written to disk.

This check and update is performed within the ext4_journal_commit_callback
function, ensuring that the superblock is written while the disk is
active, rather than based on a timer that may trigger during disk idle
periods.

Discussion https://www.spinics.net/lists/linux-ext4/msg85865.html

Signed-off-by: Vitaliy Kuznetsov <vk.en.mail@gmail.com>
---
 fs/ext4/super.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c94ebf704616..8bee05118c7a 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -433,6 +433,57 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi)
 #define ext4_get_tstamp(es, tstamp) \
 	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)

+#define EXT4_SB_REFRESH_INTERVAL_SEC (3600) /* seconds (1 hour) */
+#define EXT4_SB_REFRESH_INTERVAL_KB (16384) /* kilobytes (16MB) */
+
+/*
+ * The ext4_maybe_update_superblock() function checks and updates the
+ * superblock if needed.
+ *
+ * This function is designed to update the on-disk superblock only under
+ * certain conditions to prevent excessive disk writes and unnecessary
+ * waking of the disk from sleep. The superblock will be updated if:
+ * 1. More than an hour has passed since the last superblock update, and
+ * 2. More than 16MB have been written since the last superblock update.
+ *
+ * @sb: The superblock
+ */
+static void ext4_maybe_update_superblock(struct super_block *sb)
+{
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct ext4_super_block *es = sbi->s_es;
+	journal_t *journal = sbi->s_journal;
+	time64_t now;
+	__u64 last_update;
+	__u64 lifetime_write_kbytes;
+	__u64 diff_size;
+
+	if (sb_rdonly(sb) || !(sb->s_flags & SB_ACTIVE) ||
+	    !journal || (journal->j_flags & JBD2_UNMOUNT))
+		return;
+
+	now = ktime_get_real_seconds();
+	last_update = ext4_get_tstamp(es, s_wtime);
+
+	if (likely(now - last_update < EXT4_SB_REFRESH_INTERVAL_SEC))
+		return;
+
+	lifetime_write_kbytes = sbi->s_kbytes_written +
+		((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
+		  sbi->s_sectors_written_start) >> 1);
+
+	/* Get the number of kilobytes not written to disk to account
+	 * for statistics and compare with a multiple of 16 MB. This
+	 * is used to determine when the next superblock commit should
+	 * occur (i.e. not more often than once per 16MB if there was
+	 * less written in an hour).
+	 */
+	diff_size = lifetime_write_kbytes - le64_to_cpu(es->s_kbytes_written);
+
+	if (diff_size > EXT4_SB_REFRESH_INTERVAL_KB)
+		schedule_work(&EXT4_SB(sb)->s_error_work);
+}
+
 /*
  * The del_gendisk() function uninitializes the disk-specific data
  * structures, including the bdi structure, without telling anyone
@@ -459,6 +510,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
 	BUG_ON(txn->t_state == T_FINISHED);

 	ext4_process_freed_data(sb, txn->t_tid);
+	ext4_maybe_update_superblock(sb);

 	spin_lock(&sbi->s_md_lock);
 	while (!list_empty(&txn->t_private_list)) {
@@ -715,6 +767,7 @@ static void flush_stashed_error_work(struct work_struct *work)
 	 */
 	if (!sb_rdonly(sbi->s_sb) && journal) {
 		struct buffer_head *sbh = sbi->s_sbh;
+		bool call_notify_err;
 		handle = jbd2_journal_start(journal, 1);
 		if (IS_ERR(handle))
 			goto write_directly;
@@ -722,6 +775,10 @@ static void flush_stashed_error_work(struct work_struct *work)
 			jbd2_journal_stop(handle);
 			goto write_directly;
 		}
+
+		if (sbi->s_add_error_count > 0)
+			call_notify_err = true;
+
 		ext4_update_super(sbi->s_sb);
 		if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
 			ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to "
@@ -735,7 +792,10 @@ static void flush_stashed_error_work(struct work_struct *work)
 			goto write_directly;
 		}
 		jbd2_journal_stop(handle);
-		ext4_notify_error_sysfs(sbi);
+
+		if (call_notify_err)
+			ext4_notify_error_sysfs(sbi);
+
 		return;
 	}
 write_directly:
--
2.39.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] ext4: Add periodic superblock update check
  2023-08-10 14:38 ` [PATCH v2] " Vitaliy Kuznetsov
@ 2023-08-24  4:53   ` Theodore Ts'o
  2023-08-25 12:34     ` Jan Kara
  2023-08-26 19:58     ` [PATCH v3] " vk.en.mail
  0 siblings, 2 replies; 8+ messages in thread
From: Theodore Ts'o @ 2023-08-24  4:53 UTC (permalink / raw)
  To: linux-ext4, Vitaliy Kuznetsov; +Cc: Theodore Ts'o, adilger


On Thu, 10 Aug 2023 18:38:52 +0400, Vitaliy Kuznetsov wrote:
> This patch introduces a mechanism to periodically check and update
> the superblock within the ext4 file system. The main purpose of this
> patch is to keep the disk superblock up to date. The update will be
> performed if more than one hour has passed since the last update, and
> if more than 16MB of data have been written to disk.
> 
> This check and update is performed within the ext4_journal_commit_callback
> function, ensuring that the superblock is written while the disk is
> active, rather than based on a timer that may trigger during disk idle
> periods.
> 
> [...]

Applied, thanks!

[1/1] ext4: Add periodic superblock update check
      commit: 58d85f2e88c97c69c869cae6c6bdd1af32936146

Best regards,
-- 
Theodore Ts'o <tytso@mit.edu>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] ext4: Add periodic superblock update check
  2023-08-24  4:53   ` Theodore Ts'o
@ 2023-08-25 12:34     ` Jan Kara
  2023-08-26 19:58     ` [PATCH v3] " vk.en.mail
  1 sibling, 0 replies; 8+ messages in thread
From: Jan Kara @ 2023-08-25 12:34 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: linux-ext4, Vitaliy Kuznetsov, adilger

On Thu 24-08-23 00:53:44, Theodore Ts'o wrote:
> 
> On Thu, 10 Aug 2023 18:38:52 +0400, Vitaliy Kuznetsov wrote:
> > This patch introduces a mechanism to periodically check and update
> > the superblock within the ext4 file system. The main purpose of this
> > patch is to keep the disk superblock up to date. The update will be
> > performed if more than one hour has passed since the last update, and
> > if more than 16MB of data have been written to disk.
> > 
> > This check and update is performed within the ext4_journal_commit_callback
> > function, ensuring that the superblock is written while the disk is
> > active, rather than based on a timer that may trigger during disk idle
> > periods.
> > 
> > [...]
> 
> Applied, thanks!
> 
> [1/1] ext4: Add periodic superblock update check
>       commit: 58d85f2e88c97c69c869cae6c6bdd1af32936146

Coverity is telling me that this commit is adding uninitialized variable
access to call_notify_err and it seems to be correct... call_notify_err
needs to be initialized to 0.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3] ext4: Add periodic superblock update check
  2023-08-24  4:53   ` Theodore Ts'o
  2023-08-25 12:34     ` Jan Kara
@ 2023-08-26 19:58     ` vk.en.mail
  2023-08-28 11:48       ` Jan Kara
  1 sibling, 1 reply; 8+ messages in thread
From: vk.en.mail @ 2023-08-26 19:58 UTC (permalink / raw)
  To: linux-ext4, tytso, jack; +Cc: adilger, Vitaliy Kuznetsov

From: Vitaliy Kuznetsov <vk.en.mail@gmail.com>

This patch introduces a mechanism to periodically check and update
the superblock within the ext4 file system. The main purpose of this
patch is to keep the disk superblock up to date. The update will be
performed if more than one hour has passed since the last update, and
if more than 16MB of data have been written to disk.

This check and update is performed within the ext4_journal_commit_callback
function, ensuring that the superblock is written while the disk is
active, rather than based on a timer that may trigger during disk idle
periods.

Discussion https://www.spinics.net/lists/linux-ext4/msg85865.html

Signed-off-by: Vitaliy Kuznetsov <vk.en.mail@gmail.com>
---
 fs/ext4/super.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c94ebf704616..8bee05118c7a 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -433,6 +433,57 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi)
 #define ext4_get_tstamp(es, tstamp) \
 	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)

+#define EXT4_SB_REFRESH_INTERVAL_SEC (3600) /* seconds (1 hour) */
+#define EXT4_SB_REFRESH_INTERVAL_KB (16384) /* kilobytes (16MB) */
+
+/*
+ * The ext4_maybe_update_superblock() function checks and updates the
+ * superblock if needed.
+ *
+ * This function is designed to update the on-disk superblock only under
+ * certain conditions to prevent excessive disk writes and unnecessary
+ * waking of the disk from sleep. The superblock will be updated if:
+ * 1. More than an hour has passed since the last superblock update, and
+ * 2. More than 16MB have been written since the last superblock update.
+ *
+ * @sb: The superblock
+ */
+static void ext4_maybe_update_superblock(struct super_block *sb)
+{
+	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct ext4_super_block *es = sbi->s_es;
+	journal_t *journal = sbi->s_journal;
+	time64_t now;
+	__u64 last_update;
+	__u64 lifetime_write_kbytes;
+	__u64 diff_size;
+
+	if (sb_rdonly(sb) || !(sb->s_flags & SB_ACTIVE) ||
+	    !journal || (journal->j_flags & JBD2_UNMOUNT))
+		return;
+
+	now = ktime_get_real_seconds();
+	last_update = ext4_get_tstamp(es, s_wtime);
+
+	if (likely(now - last_update < EXT4_SB_REFRESH_INTERVAL_SEC))
+		return;
+
+	lifetime_write_kbytes = sbi->s_kbytes_written +
+		((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
+		  sbi->s_sectors_written_start) >> 1);
+
+	/* Get the number of kilobytes not written to disk to account
+	 * for statistics and compare with a multiple of 16 MB. This
+	 * is used to determine when the next superblock commit should
+	 * occur (i.e. not more often than once per 16MB if there was
+	 * less written in an hour).
+	 */
+	diff_size = lifetime_write_kbytes - le64_to_cpu(es->s_kbytes_written);
+
+	if (diff_size > EXT4_SB_REFRESH_INTERVAL_KB)
+		schedule_work(&EXT4_SB(sb)->s_error_work);
+}
+
 /*
  * The del_gendisk() function uninitializes the disk-specific data
  * structures, including the bdi structure, without telling anyone
@@ -459,6 +510,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
 	BUG_ON(txn->t_state == T_FINISHED);

 	ext4_process_freed_data(sb, txn->t_tid);
+	ext4_maybe_update_superblock(sb);

 	spin_lock(&sbi->s_md_lock);
 	while (!list_empty(&txn->t_private_list)) {
@@ -715,6 +767,7 @@ static void flush_stashed_error_work(struct work_struct *work)
 	 */
 	if (!sb_rdonly(sbi->s_sb) && journal) {
 		struct buffer_head *sbh = sbi->s_sbh;
+		bool call_notify_err = false;
 		handle = jbd2_journal_start(journal, 1);
 		if (IS_ERR(handle))
 			goto write_directly;
@@ -722,6 +775,10 @@ static void flush_stashed_error_work(struct work_struct *work)
 			jbd2_journal_stop(handle);
 			goto write_directly;
 		}
+
+		if (sbi->s_add_error_count > 0)
+			call_notify_err = true;
+
 		ext4_update_super(sbi->s_sb);
 		if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
 			ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to "
@@ -735,7 +792,10 @@ static void flush_stashed_error_work(struct work_struct *work)
 			goto write_directly;
 		}
 		jbd2_journal_stop(handle);
-		ext4_notify_error_sysfs(sbi);
+
+		if (call_notify_err)
+			ext4_notify_error_sysfs(sbi);
+
 		return;
 	}
 write_directly:
--
2.39.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v3] ext4: Add periodic superblock update check
  2023-08-26 19:58     ` [PATCH v3] " vk.en.mail
@ 2023-08-28 11:48       ` Jan Kara
  0 siblings, 0 replies; 8+ messages in thread
From: Jan Kara @ 2023-08-28 11:48 UTC (permalink / raw)
  To: vk.en.mail; +Cc: linux-ext4, tytso, jack, adilger

On Sat 26-08-23 23:58:41, vk.en.mail@gmail.com wrote:
> From: Vitaliy Kuznetsov <vk.en.mail@gmail.com>
> 
> This patch introduces a mechanism to periodically check and update
> the superblock within the ext4 file system. The main purpose of this
> patch is to keep the disk superblock up to date. The update will be
> performed if more than one hour has passed since the last update, and
> if more than 16MB of data have been written to disk.
> 
> This check and update is performed within the ext4_journal_commit_callback
> function, ensuring that the superblock is written while the disk is
> active, rather than based on a timer that may trigger during disk idle
> periods.
> 
> Discussion https://www.spinics.net/lists/linux-ext4/msg85865.html
> 
> Signed-off-by: Vitaliy Kuznetsov <vk.en.mail@gmail.com>

Looks good to me. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  fs/ext4/super.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 61 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index c94ebf704616..8bee05118c7a 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -433,6 +433,57 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi)
>  #define ext4_get_tstamp(es, tstamp) \
>  	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)
> 
> +#define EXT4_SB_REFRESH_INTERVAL_SEC (3600) /* seconds (1 hour) */
> +#define EXT4_SB_REFRESH_INTERVAL_KB (16384) /* kilobytes (16MB) */
> +
> +/*
> + * The ext4_maybe_update_superblock() function checks and updates the
> + * superblock if needed.
> + *
> + * This function is designed to update the on-disk superblock only under
> + * certain conditions to prevent excessive disk writes and unnecessary
> + * waking of the disk from sleep. The superblock will be updated if:
> + * 1. More than an hour has passed since the last superblock update, and
> + * 2. More than 16MB have been written since the last superblock update.
> + *
> + * @sb: The superblock
> + */
> +static void ext4_maybe_update_superblock(struct super_block *sb)
> +{
> +	struct ext4_sb_info *sbi = EXT4_SB(sb);
> +	struct ext4_super_block *es = sbi->s_es;
> +	journal_t *journal = sbi->s_journal;
> +	time64_t now;
> +	__u64 last_update;
> +	__u64 lifetime_write_kbytes;
> +	__u64 diff_size;
> +
> +	if (sb_rdonly(sb) || !(sb->s_flags & SB_ACTIVE) ||
> +	    !journal || (journal->j_flags & JBD2_UNMOUNT))
> +		return;
> +
> +	now = ktime_get_real_seconds();
> +	last_update = ext4_get_tstamp(es, s_wtime);
> +
> +	if (likely(now - last_update < EXT4_SB_REFRESH_INTERVAL_SEC))
> +		return;
> +
> +	lifetime_write_kbytes = sbi->s_kbytes_written +
> +		((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
> +		  sbi->s_sectors_written_start) >> 1);
> +
> +	/* Get the number of kilobytes not written to disk to account
> +	 * for statistics and compare with a multiple of 16 MB. This
> +	 * is used to determine when the next superblock commit should
> +	 * occur (i.e. not more often than once per 16MB if there was
> +	 * less written in an hour).
> +	 */
> +	diff_size = lifetime_write_kbytes - le64_to_cpu(es->s_kbytes_written);
> +
> +	if (diff_size > EXT4_SB_REFRESH_INTERVAL_KB)
> +		schedule_work(&EXT4_SB(sb)->s_error_work);
> +}
> +
>  /*
>   * The del_gendisk() function uninitializes the disk-specific data
>   * structures, including the bdi structure, without telling anyone
> @@ -459,6 +510,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
>  	BUG_ON(txn->t_state == T_FINISHED);
> 
>  	ext4_process_freed_data(sb, txn->t_tid);
> +	ext4_maybe_update_superblock(sb);
> 
>  	spin_lock(&sbi->s_md_lock);
>  	while (!list_empty(&txn->t_private_list)) {
> @@ -715,6 +767,7 @@ static void flush_stashed_error_work(struct work_struct *work)
>  	 */
>  	if (!sb_rdonly(sbi->s_sb) && journal) {
>  		struct buffer_head *sbh = sbi->s_sbh;
> +		bool call_notify_err = false;
>  		handle = jbd2_journal_start(journal, 1);
>  		if (IS_ERR(handle))
>  			goto write_directly;
> @@ -722,6 +775,10 @@ static void flush_stashed_error_work(struct work_struct *work)
>  			jbd2_journal_stop(handle);
>  			goto write_directly;
>  		}
> +
> +		if (sbi->s_add_error_count > 0)
> +			call_notify_err = true;
> +
>  		ext4_update_super(sbi->s_sb);
>  		if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
>  			ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to "
> @@ -735,7 +792,10 @@ static void flush_stashed_error_work(struct work_struct *work)
>  			goto write_directly;
>  		}
>  		jbd2_journal_stop(handle);
> -		ext4_notify_error_sysfs(sbi);
> +
> +		if (call_notify_err)
> +			ext4_notify_error_sysfs(sbi);
> +
>  		return;
>  	}
>  write_directly:
> --
> 2.39.2
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-08-28 11:49 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-31 12:25 [PATCH] ext4: Add periodic superblock update check Vitaliy Kuznetsov
2023-08-02 21:18 ` Andreas Dilger
2023-08-04 20:58 ` Theodore Ts'o
2023-08-10 14:38 ` [PATCH v2] " Vitaliy Kuznetsov
2023-08-24  4:53   ` Theodore Ts'o
2023-08-25 12:34     ` Jan Kara
2023-08-26 19:58     ` [PATCH v3] " vk.en.mail
2023-08-28 11:48       ` Jan Kara

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.