* [PATCH] btrfs: track current commit duration in commit_stats
@ 2025-04-24 23:56 Boris Burkov
2025-04-25 11:42 ` David Sterba
2025-04-29 8:27 ` David Sterba
0 siblings, 2 replies; 4+ messages in thread
From: Boris Burkov @ 2025-04-24 23:56 UTC (permalink / raw)
To: linux-btrfs, kernel-team
When debugging/detecting outlier commit stalls, having an indicator that
we are currently in a long commit critical section can be very useful.
Extend the commit_stats sysfs file to also include the current commit
critical section duration.
Since this requires storing the last commit start time, use that rather
than a separate stack variable for storing the finished commit durations
as well.
Signed-off-by: Boris Burkov <boris@bur.io>
---
fs/btrfs/fs.h | 2 ++
fs/btrfs/sysfs.c | 8 ++++++++
fs/btrfs/transaction.c | 17 +++++++++--------
3 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
index bcca43046064..1f375170cdcb 100644
--- a/fs/btrfs/fs.h
+++ b/fs/btrfs/fs.h
@@ -419,6 +419,8 @@ struct btrfs_commit_stats {
u64 last_commit_dur;
/* The total commit duration in ns */
u64 total_commit_dur;
+ /* Start of the last critical section in ns. */
+ u64 start_time;
};
struct btrfs_fs_info {
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index b9af74498b0c..4e35b4bfffaa 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -1138,13 +1138,21 @@ static ssize_t btrfs_commit_stats_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+ u64 now = ktime_get_ns();
+ u64 start_time = fs_info->commit_stats.start_time;
+ u64 pending = 0;
+
+ if (start_time)
+ pending = now - start_time;
return sysfs_emit(buf,
"commits %llu\n"
+ "cur_commit_ms %llu\n"
"last_commit_ms %llu\n"
"max_commit_ms %llu\n"
"total_commit_ms %llu\n",
fs_info->commit_stats.commit_count,
+ div_u64(pending, NSEC_PER_MSEC),
div_u64(fs_info->commit_stats.last_commit_dur, NSEC_PER_MSEC),
div_u64(fs_info->commit_stats.max_commit_dur, NSEC_PER_MSEC),
div_u64(fs_info->commit_stats.total_commit_dur, NSEC_PER_MSEC));
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 39e48bf610a1..02e6926d53bd 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -2164,13 +2164,19 @@ static void add_pending_snapshot(struct btrfs_trans_handle *trans)
list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
}
-static void update_commit_stats(struct btrfs_fs_info *fs_info, ktime_t interval)
+static void update_commit_stats(struct btrfs_fs_info *fs_info)
{
+ ktime_t now = ktime_get_ns();
+ ktime_t interval = now - fs_info->commit_stats.start_time;
+
+ ASSERT(fs_info->commit_stats.start_time);
+
fs_info->commit_stats.commit_count++;
fs_info->commit_stats.last_commit_dur = interval;
fs_info->commit_stats.max_commit_dur =
max_t(u64, fs_info->commit_stats.max_commit_dur, interval);
fs_info->commit_stats.total_commit_dur += interval;
+ fs_info->commit_stats.start_time = 0;
}
int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
@@ -2179,8 +2185,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
struct btrfs_transaction *cur_trans = trans->transaction;
struct btrfs_transaction *prev_trans = NULL;
int ret;
- ktime_t start_time;
- ktime_t interval;
ASSERT(refcount_read(&trans->use_count) == 1);
btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_PREP);
@@ -2314,7 +2318,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
* Get the time spent on the work done by the commit thread and not
* the time spent waiting on a previous commit
*/
- start_time = ktime_get_ns();
+ fs_info->commit_stats.start_time = ktime_get_ns();
extwriter_counter_dec(cur_trans, trans->type);
@@ -2568,6 +2572,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
cur_trans->state = TRANS_STATE_COMPLETED;
wake_up(&cur_trans->commit_wait);
btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
+ update_commit_stats(fs_info);
spin_lock(&fs_info->trans_lock);
list_del_init(&cur_trans->list);
@@ -2581,8 +2586,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
trace_btrfs_transaction_commit(fs_info);
- interval = ktime_get_ns() - start_time;
-
btrfs_scrub_continue(fs_info);
if (current->journal_info == trans)
@@ -2590,8 +2593,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
kmem_cache_free(btrfs_trans_handle_cachep, trans);
- update_commit_stats(fs_info, interval);
-
return ret;
unlock_reloc:
--
2.49.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] btrfs: track current commit duration in commit_stats
2025-04-24 23:56 [PATCH] btrfs: track current commit duration in commit_stats Boris Burkov
@ 2025-04-25 11:42 ` David Sterba
2025-04-29 8:27 ` David Sterba
1 sibling, 0 replies; 4+ messages in thread
From: David Sterba @ 2025-04-25 11:42 UTC (permalink / raw)
To: Boris Burkov; +Cc: linux-btrfs, kernel-team
On Thu, Apr 24, 2025 at 04:56:34PM -0700, Boris Burkov wrote:
> When debugging/detecting outlier commit stalls, having an indicator that
> we are currently in a long commit critical section can be very useful.
> Extend the commit_stats sysfs file to also include the current commit
> critical section duration.
>
> Since this requires storing the last commit start time, use that rather
> than a separate stack variable for storing the finished commit durations
> as well.
>
> Signed-off-by: Boris Burkov <boris@bur.io>
Reviewed-by: David Sterba <dsterba@suse.com>
> --- a/fs/btrfs/sysfs.c
> +++ b/fs/btrfs/sysfs.c
> @@ -1138,13 +1138,21 @@ static ssize_t btrfs_commit_stats_show(struct kobject *kobj,
> struct kobj_attribute *a, char *buf)
> {
> struct btrfs_fs_info *fs_info = to_fs_info(kobj);
> + u64 now = ktime_get_ns();
> + u64 start_time = fs_info->commit_stats.start_time;
> + u64 pending = 0;
> +
> + if (start_time)
> + pending = now - start_time;
>
> return sysfs_emit(buf,
> "commits %llu\n"
> + "cur_commit_ms %llu\n"
> "last_commit_ms %llu\n"
> "max_commit_ms %llu\n"
> "total_commit_ms %llu\n",
This ordering looks logical, the presence of order should not be assumed
by applications, this is line oriented so a grep should always work.
> fs_info->commit_stats.commit_count,
> + div_u64(pending, NSEC_PER_MSEC),
> div_u64(fs_info->commit_stats.last_commit_dur, NSEC_PER_MSEC),
> div_u64(fs_info->commit_stats.max_commit_dur, NSEC_PER_MSEC),
> div_u64(fs_info->commit_stats.total_commit_dur, NSEC_PER_MSEC));
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] btrfs: track current commit duration in commit_stats
2025-04-24 23:56 [PATCH] btrfs: track current commit duration in commit_stats Boris Burkov
2025-04-25 11:42 ` David Sterba
@ 2025-04-29 8:27 ` David Sterba
2025-04-29 9:03 ` David Sterba
1 sibling, 1 reply; 4+ messages in thread
From: David Sterba @ 2025-04-29 8:27 UTC (permalink / raw)
To: Boris Burkov; +Cc: linux-btrfs, kernel-team
On Thu, Apr 24, 2025 at 04:56:34PM -0700, Boris Burkov wrote:
> When debugging/detecting outlier commit stalls, having an indicator that
> we are currently in a long commit critical section can be very useful.
> Extend the commit_stats sysfs file to also include the current commit
> critical section duration.
>
> Since this requires storing the last commit start time, use that rather
> than a separate stack variable for storing the finished commit durations
> as well.
>
> Signed-off-by: Boris Burkov <boris@bur.io>
> ---
> fs/btrfs/fs.h | 2 ++
> fs/btrfs/sysfs.c | 8 ++++++++
> fs/btrfs/transaction.c | 17 +++++++++--------
> 3 files changed, 19 insertions(+), 8 deletions(-)
>
> diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
> index bcca43046064..1f375170cdcb 100644
> --- a/fs/btrfs/fs.h
> +++ b/fs/btrfs/fs.h
> @@ -419,6 +419,8 @@ struct btrfs_commit_stats {
> u64 last_commit_dur;
> /* The total commit duration in ns */
> u64 total_commit_dur;
> + /* Start of the last critical section in ns. */
> + u64 start_time;
> };
>
> struct btrfs_fs_info {
> diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
> index b9af74498b0c..4e35b4bfffaa 100644
> --- a/fs/btrfs/sysfs.c
> +++ b/fs/btrfs/sysfs.c
> @@ -1138,13 +1138,21 @@ static ssize_t btrfs_commit_stats_show(struct kobject *kobj,
> struct kobj_attribute *a, char *buf)
> {
> struct btrfs_fs_info *fs_info = to_fs_info(kobj);
> + u64 now = ktime_get_ns();
> + u64 start_time = fs_info->commit_stats.start_time;
> + u64 pending = 0;
> +
> + if (start_time)
> + pending = now - start_time;
>
> return sysfs_emit(buf,
> "commits %llu\n"
> + "cur_commit_ms %llu\n"
> "last_commit_ms %llu\n"
> "max_commit_ms %llu\n"
> "total_commit_ms %llu\n",
> fs_info->commit_stats.commit_count,
> + div_u64(pending, NSEC_PER_MSEC),
> div_u64(fs_info->commit_stats.last_commit_dur, NSEC_PER_MSEC),
> div_u64(fs_info->commit_stats.max_commit_dur, NSEC_PER_MSEC),
> div_u64(fs_info->commit_stats.total_commit_dur, NSEC_PER_MSEC));
> diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
> index 39e48bf610a1..02e6926d53bd 100644
> --- a/fs/btrfs/transaction.c
> +++ b/fs/btrfs/transaction.c
> @@ -2164,13 +2164,19 @@ static void add_pending_snapshot(struct btrfs_trans_handle *trans)
> list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
> }
>
> -static void update_commit_stats(struct btrfs_fs_info *fs_info, ktime_t interval)
> +static void update_commit_stats(struct btrfs_fs_info *fs_info)
> {
> + ktime_t now = ktime_get_ns();
> + ktime_t interval = now - fs_info->commit_stats.start_time;
> +
> + ASSERT(fs_info->commit_stats.start_time);
[ 2469.533069] assertion failed: fs_info->commit_stats.start_time :: 0, in fs/btrfs/transaction.c:2172
[ 2469.536071] ------------[ cut here ]------------
[ 2469.537543] kernel BUG at fs/btrfs/transaction.c:2172!
[ 2469.539158] Oops: invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN
[ 2469.541112] CPU: 11 UID: 0 PID: 4140 Comm: fsstress Not tainted 6.15.0-rc4-default+ #109 PREEMPT(full)
[ 2469.543907] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-3-gd478f380-rebuilt.opensuse.org 04/01/2014
[ 2469.547238] RIP: 0010:btrfs_commit_transaction.cold+0x126/0x1dd [btrfs]
[ 2469.554618] RSP: 0018:ffff8880059dfc58 EFLAGS: 00010282
[ 2469.556210] RAX: 0000000000000057 RBX: ffff888006414000 RCX: 0000000000000000
[ 2469.558319] RDX: 0000000000000057 RSI: 0000000000000004 RDI: ffffed1000b3bf7e
[ 2469.560427] RBP: 0000000000000000 R08: 0000000000000000 R09: fffffbfff54e5f34
[ 2469.562575] R10: 0000000000000003 R11: 0000000000000001 R12: ffff88800374e800
[ 2469.564682] R13: 0000023eedb59554 R14: ffff88800374e8f8 R15: ffff88800b01a948
[ 2469.566788] FS: 00007f590f740180(0000) GS:ffff8880bab98000(0000) knlGS:0000000000000000
[ 2469.569219] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2469.570971] CR2: 00007f416fd9e038 CR3: 000000001f3ee000 CR4: 00000000000006b0
[ 2469.573076] Call Trace:
[ 2469.573954] <TASK>
[ 2469.574737] ? cleanup_transaction+0x1a0/0x1a0 [btrfs]
[ 2469.576421] ? __lock_release.isra.0+0xc1/0x2e0
[ 2469.577847] ? preempt_count_add+0x79/0x150
[ 2469.579171] ? __up_write+0x1b3/0x520
[ 2469.580377] ? btrfs_sync_file+0xb4b/0xd30 [btrfs]
[ 2469.581961] btrfs_sync_file+0x740/0xd30 [btrfs]
[ 2469.583507] ? start_ordered_ops.constprop.0+0x100/0x100 [btrfs]
[ 2469.585406] do_fsync+0x39/0x70
[ 2469.586475] __x64_sys_fsync+0x2e/0x40
[ 2469.587693] do_syscall_64+0x6d/0x140
[ 2469.588894] entry_SYSCALL_64_after_hwframe+0x4b/0x53
[ 2469.590461] RIP: 0033:0x7f590f853874
[ 2469.591626] Code: 00 e9 a0 5b f1 ff 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 90 90 80 3d 35 81 0f 00 00 74 13 b8 4a 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 44 c3 0f 1f 00 48 83 ec 18 89 7c 24 0c e8 b1
[ 2469.596956] RSP: 002b:00007fffe09524d8 EFLAGS: 00000202 ORIG_RAX: 000000000000004a
[ 2469.599242] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f590f853874
[ 2469.601341] RDX: 0000000000000103 RSI: 0000000000411059 RDI: 0000000000000004
[ 2469.603429] RBP: 0000000000001049 R08: fefefefefefefeff R09: 00007fffe09524ec
[ 2469.605525] R10: 0000000000000000 R11: 0000000000000202 R12: 00007fffe09524f0
[ 2469.607631] R13: 0000000000000000 R14: 00007fffe0952590 R15: 000000000040cdc0
[ 2469.609742] </TASK>
[ 2469.610552] Modules linked in: btrfs blake2b_generic xor lzo_compress lzo_decompress raid6_pq zstd_decompress zstd_compress zstd_common xxhash loop
[ 2469.614356] ---[ end trace 0000000000000000 ]---
[ 2469.615800] RIP: 0010:btrfs_commit_transaction.cold+0x126/0x1dd [btrfs]
[ 2469.623202] RSP: 0018:ffff8880059dfc58 EFLAGS: 00010282
[ 2469.624798] RAX: 0000000000000057 RBX: ffff888006414000 RCX: 0000000000000000
[ 2469.626912] RDX: 0000000000000057 RSI: 0000000000000004 RDI: ffffed1000b3bf7e
[ 2469.629000] RBP: 0000000000000000 R08: 0000000000000000 R09: fffffbfff54e5f34
[ 2469.631125] R10: 0000000000000003 R11: 0000000000000001 R12: ffff88800374e800
[ 2469.633231] R13: 0000023eedb59554 R14: ffff88800374e8f8 R15: ffff88800b01a948
[ 2469.635350] FS: 00007f590f740180(0000) GS:ffff8880bab98000(0000) knlGS:0000000000000000
[ 2469.637818] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2469.639568] CR2: 00007f416fd9e038 CR3: 000000001f3ee000 CR4: 00000000000006b0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] btrfs: track current commit duration in commit_stats
2025-04-29 8:27 ` David Sterba
@ 2025-04-29 9:03 ` David Sterba
0 siblings, 0 replies; 4+ messages in thread
From: David Sterba @ 2025-04-29 9:03 UTC (permalink / raw)
To: David Sterba; +Cc: Boris Burkov, linux-btrfs, kernel-team
On Tue, Apr 29, 2025 at 10:27:11AM +0200, David Sterba wrote:
> On Thu, Apr 24, 2025 at 04:56:34PM -0700, Boris Burkov wrote:
> > When debugging/detecting outlier commit stalls, having an indicator that
> > we are currently in a long commit critical section can be very useful.
> > Extend the commit_stats sysfs file to also include the current commit
> > critical section duration.
> >
> > Since this requires storing the last commit start time, use that rather
> > than a separate stack variable for storing the finished commit durations
> > as well.
> >
> > Signed-off-by: Boris Burkov <boris@bur.io>
> > ---
> > fs/btrfs/fs.h | 2 ++
> > fs/btrfs/sysfs.c | 8 ++++++++
> > fs/btrfs/transaction.c | 17 +++++++++--------
> > 3 files changed, 19 insertions(+), 8 deletions(-)
> >
> > diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
> > index bcca43046064..1f375170cdcb 100644
> > --- a/fs/btrfs/fs.h
> > +++ b/fs/btrfs/fs.h
> > @@ -419,6 +419,8 @@ struct btrfs_commit_stats {
> > u64 last_commit_dur;
> > /* The total commit duration in ns */
> > u64 total_commit_dur;
> > + /* Start of the last critical section in ns. */
> > + u64 start_time;
> > };
> >
> > struct btrfs_fs_info {
> > diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
> > index b9af74498b0c..4e35b4bfffaa 100644
> > --- a/fs/btrfs/sysfs.c
> > +++ b/fs/btrfs/sysfs.c
> > @@ -1138,13 +1138,21 @@ static ssize_t btrfs_commit_stats_show(struct kobject *kobj,
> > struct kobj_attribute *a, char *buf)
> > {
> > struct btrfs_fs_info *fs_info = to_fs_info(kobj);
> > + u64 now = ktime_get_ns();
> > + u64 start_time = fs_info->commit_stats.start_time;
> > + u64 pending = 0;
> > +
> > + if (start_time)
> > + pending = now - start_time;
> >
> > return sysfs_emit(buf,
> > "commits %llu\n"
> > + "cur_commit_ms %llu\n"
> > "last_commit_ms %llu\n"
> > "max_commit_ms %llu\n"
> > "total_commit_ms %llu\n",
> > fs_info->commit_stats.commit_count,
> > + div_u64(pending, NSEC_PER_MSEC),
> > div_u64(fs_info->commit_stats.last_commit_dur, NSEC_PER_MSEC),
> > div_u64(fs_info->commit_stats.max_commit_dur, NSEC_PER_MSEC),
> > div_u64(fs_info->commit_stats.total_commit_dur, NSEC_PER_MSEC));
> > diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
> > index 39e48bf610a1..02e6926d53bd 100644
> > --- a/fs/btrfs/transaction.c
> > +++ b/fs/btrfs/transaction.c
> > @@ -2164,13 +2164,19 @@ static void add_pending_snapshot(struct btrfs_trans_handle *trans)
> > list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
> > }
> >
> > -static void update_commit_stats(struct btrfs_fs_info *fs_info, ktime_t interval)
> > +static void update_commit_stats(struct btrfs_fs_info *fs_info)
> > {
> > + ktime_t now = ktime_get_ns();
> > + ktime_t interval = now - fs_info->commit_stats.start_time;
> > +
> > + ASSERT(fs_info->commit_stats.start_time);
>
> [ 2469.533069] assertion failed: fs_info->commit_stats.start_time :: 0, in fs/btrfs/transaction.c:2172
Quite reliably (2/2) in btrfs/028 so I'll remove the patch from
for-next for now.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-04-29 9:03 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-24 23:56 [PATCH] btrfs: track current commit duration in commit_stats Boris Burkov
2025-04-25 11:42 ` David Sterba
2025-04-29 8:27 ` David Sterba
2025-04-29 9:03 ` David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox