All of lore.kernel.org
 help / color / mirror / Atom feed
* Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
@ 2026-10-09 15:34 Naulls, Peter
  2026-10-13 14:41 ` Sebastian Andrzej Siewior
       [not found] ` <SJ0PR17MB4288FC2E7FFB577F5D6C6D9EBB9E2@SJ0PR17MB4288.namprd17.prod.outlook.com>
  0 siblings, 2 replies; 7+ messages in thread
From: Naulls, Peter @ 2026-10-09 15:34 UTC (permalink / raw)
  To: linux-rt-users@vger.kernel.org

Long term kernel hacker, but very infrequent contributor. 

We are using the RT kernel patch on x86 under kernel 6.6.78-rt51. Specifically, this is the kernel from meta-intel in Yocto Scarthgap in the intel-kernel-rt recipe. 

It appears under some high load conditions, and especially triggered by calls to sync(), there is a live lock condition in the btrfs code. I used copilot for this analysis, with apologies due here where relevant. I'm familiar with kernel code, and I'm well aware how complex filesystem interactions can be. 

Here is the lock we observe:


sync (PID 52371)
  btrfs_commit_transaction+0xc48
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  btrfs_sync_fs
  sync_fs_one_sb
  ksys_sync

ordered-I/O completion workers
  join_transaction+0x2b
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  start_transaction
  btrfs_join_transaction
  btrfs_finish_one_ordered
  btrfs_work_helper

journal/fsync callers
  wait_current_trans+0x33
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  start_transaction
  btrfs_start_transaction
  btrfs_sync_file
  vfs_fsync_range
  fsync

btrfs-transaction thread
  transaction_kthread+0x76
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  kthread


The processes are then not killable, indicting a kernel thread problem. 

This was largely found because our userspace code calls sync() excessively (being separately addressed), although that's not the proximate cause. We ended up writing shell script which writes blocks of data to a brtfs partition over several threads and also calls sync and were able to repeat it within 10s of seconds. It is not repeatable in the non-RT kernel.

To add:

I have been extensively through the later kernels in 6.6, and later series and have not found any direct fixe or references for this. I've also been through the latest RT changes and btrfs mailing lists/changes (and this post might be served better there) and cannot find any direct reference to this. The only close match is:

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=99da896614d17e8a84aeb2b2d464ac046cc8633d

This is in related code. I put this patch into our 6.6.78 kernel and it did not resolve the problem. 

With that in mind, I had copilot (again, apologies) have an attempt. It came up with this:

# Experimental mitigation for a suspected PREEMPT_RT Btrfs transaction-waiter
# livelock. wait_for_commit() can reselect a completed transaction that remains
# on trans_list after its waiters are woken. Skip completed entries while still
# waiting for older incomplete transactions. This is a diagnostic hypothesis,
# not a confirmed fix for the observed lockup.
# Review notes: the scan is O(n) under trans_lock. Completion state is published
# locklessly elsewhere; READ_ONCE provides a single load, not acquire ordering.
# A multi-hour run did not reproduce the issue, but the lock owner and root cause
# remain unknown.
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index e15e1855fa0a..0f05fabe451c 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -865,6 +865,7 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
                                     const enum btrfs_trans_state min_state)
 {
        struct btrfs_fs_info *fs_info = commit->fs_info;
+       struct btrfs_transaction *next;
        u64 transid = commit->transid;
        bool put = false;

@@ -893,10 +894,16 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
                 */

                spin_lock(&fs_info->trans_lock);
-               commit = list_first_entry_or_null(&fs_info->trans_list,
-                                                 struct btrfs_transaction,
-                                                 list);
-               if (!commit || commit->transid > transid) {
+               commit = NULL;
+               list_for_each_entry(next, &fs_info->trans_list, list) {
+                       if (next->transid > transid)
+                               break;
+                       if (READ_ONCE(next->state) == TRANS_STATE_COMPLETED)
+                               continue;
+                       commit = next;
+                       break;
+               }
+               if (!commit) {
                        spin_unlock(&fs_info->trans_lock);
                        break;
                }


Note the O(N) time here. To that end, this is very unlikely to be the correct fix, but I hope it highlights the core problem. I ran this patch for several hours with no apparent problem (versus seconds of a lockup in previous testing). 

If there's a later kernel patch I've missed, or something else I ought to be looking at or test or need more info, please let me know. 



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

* Re: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
  2026-10-09 15:34 Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78 Naulls, Peter
@ 2026-10-13 14:41 ` Sebastian Andrzej Siewior
  2026-10-13 15:29   ` [EXTERNAL] " Naulls, Peter
       [not found] ` <SJ0PR17MB4288FC2E7FFB577F5D6C6D9EBB9E2@SJ0PR17MB4288.namprd17.prod.outlook.com>
  1 sibling, 1 reply; 7+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-10-13 14:41 UTC (permalink / raw)
  To: Naulls, Peter; +Cc: linux-rt-users@vger.kernel.org

On 2026-10-09 15:34:02 [+0000], Naulls, Peter wrote:
> Long term kernel hacker, but very infrequent contributor. 
Hi Peter,

> We are using the RT kernel patch on x86 under kernel 6.6.78-rt51.
> Specifically, this is the kernel from meta-intel in Yocto Scarthgap in
> the intel-kernel-rt recipe. 
…
> sync (PID 52371)
>   btrfs_commit_transaction+0xc48
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   btrfs_sync_fs
>   sync_fs_one_sb
>   ksys_sync

This sort of sounds like the state is TRANS_STATE_SUPER_COMMITTED but is
not making progress after that. Are there any tasks involved that run at
realtime priority and would block other tasks from making progress?

…
> This is in related code. I put this patch into our 6.6.78 kernel and it did not resolve the problem. 
…
> # Experimental mitigation for a suspected PREEMPT_RT Btrfs transaction-waiter
> # livelock. wait_for_commit() can reselect a completed transaction that remains
> # on trans_list after its waiters are woken. Skip completed entries while still
> # waiting for older incomplete transactions. This is a diagnostic hypothesis,
> # not a confirmed fix for the observed lockup.
> # Review notes: the scan is O(n) under trans_lock. Completion state is published
> # locklessly elsewhere; READ_ONCE provides a single load, not acquire ordering.
> # A multi-hour run did not reproduce the issue, but the lock owner and root cause
> # remain unknown.
> diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
> index e15e1855fa0a..0f05fabe451c 100644
> --- a/fs/btrfs/transaction.c
> +++ b/fs/btrfs/transaction.c
> @@ -865,6 +865,7 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
>                                      const enum btrfs_trans_state min_state)
>  {
>         struct btrfs_fs_info *fs_info = commit->fs_info;
> +       struct btrfs_transaction *next;
>         u64 transid = commit->transid;
>         bool put = false;
> 
> @@ -893,10 +894,16 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
>                  */
> 
>                 spin_lock(&fs_info->trans_lock);
> -               commit = list_first_entry_or_null(&fs_info->trans_list,
> -                                                 struct btrfs_transaction,
> -                                                 list);
> -               if (!commit || commit->transid > transid) {
> +               commit = NULL;
> +               list_for_each_entry(next, &fs_info->trans_list, list) {
> +                       if (next->transid > transid)
> +                               break;
> +                       if (READ_ONCE(next->state) == TRANS_STATE_COMPLETED)
> +                               continue;
> +                       commit = next;
> +                       break;
> +               }
> +               if (!commit) {
>                         spin_unlock(&fs_info->trans_lock);
>                         break;
>                 }
> 
> 
> Note the O(N) time here. To that end, this is very unlikely to be the
> correct fix, but I hope it highlights the core problem. I ran this
> patch for several hours with no apparent problem (versus seconds of a
> lockup in previous testing). 
> 
> If there's a later kernel patch I've missed, or something else I ought
> to be looking at or test or need more info, please let me know. 

PREEMPT_RT shouldn't do much different than !PREEMPT_RT. Do you have
tasks with different priorities? If that is the case then it might be
that one thread is blocking another thread that should make progress.
Your changes iterates over TRANS_STATE_COMPLETED so it seems that it is
not cleaned up for some reason.

Could you try if you can reproduce this with v7.3-rc7? This one does not
require any additional patches.
I'm not sure if this report would help the btrfs folks to recognize if
this is a solved problem or where the issue might be.

Sebastian

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

* Re: [EXTERNAL] Re: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
  2026-10-13 14:41 ` Sebastian Andrzej Siewior
@ 2026-10-13 15:29   ` Naulls, Peter
  2026-10-13 15:52     ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 7+ messages in thread
From: Naulls, Peter @ 2026-10-13 15:29 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: linux-rt-users@vger.kernel.org

With apologies for Outlook formatting, it's not my first choice. 

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

> This sort of sounds like the state is TRANS_STATE_SUPER_COMMITTED but is
> not making progress after that. Are there any tasks involved that run at
> realtime priority and would block other tasks from making progress?

I won't say it's impossible, but it's not likely. We have a monolithic app which is disabled for this test. There 
may be other subsystems writing to the log. To the best of my knowledge though, there's been no adjustment
of priorities (we are experimenting with this, but it's inside the app and wasn't turned on for this test)  vs default 
Linux setup - it is Yocto using a largely standard setup. 

> PREEMPT_RT shouldn't do much different than !PREEMPT_RT. Do you have
> tasks with different priorities? If that is the case then it might be
> that one thread is blocking another thread that should make progress.
> Your changes iterates over TRANS_STATE_COMPLETED so it seems that it is
> not cleaned up for some reason.

As you say; this is not my expertise. 

> Could you try if you can reproduce this with v7.3-rc7? This one does not
> require any additional patches.
> I'm not sure if this report would help the btrfs folks to recognize if
> this is a solved problem or where the issue might be.

Trying a later kernel is not impossible, but it somewhat time consuming, I will have to strip a number of things from the build, 
and Yocto doesn't make this particularly straightforward, and might even compromise the test. We will update the kernel 
in due course, but you'll understand I'd prefer not to commit this time without some degree of confirmation here.  As things
stand right now, it may be that we just run without RT, but it would be good to at least verify this, and have a record for 
other people. 

As for brtfs, yes that was my next follow up, I had been just about to do that before your reply. 

Regards. 

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

* Re: [EXTERNAL] Re: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
  2026-10-13 15:29   ` [EXTERNAL] " Naulls, Peter
@ 2026-10-13 15:52     ` Sebastian Andrzej Siewior
  0 siblings, 0 replies; 7+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-10-13 15:52 UTC (permalink / raw)
  To: Naulls, Peter; +Cc: linux-rt-users@vger.kernel.org

On 2026-10-13 15:29:39 [+0000], Naulls, Peter wrote:
> With apologies for Outlook formatting, it's not my first choice. 
> 
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> > This sort of sounds like the state is TRANS_STATE_SUPER_COMMITTED but is
> > not making progress after that. Are there any tasks involved that run at
> > realtime priority and would block other tasks from making progress?
> 
> I won't say it's impossible, but it's not likely. We have a monolithic app which is disabled for this test. There 
> may be other subsystems writing to the log. To the best of my knowledge though, there's been no adjustment
> of priorities (we are experimenting with this, but it's inside the app and wasn't turned on for this test)  vs default 
> Linux setup - it is Yocto using a largely standard setup. 

in that case ps should report just SCHED_OTHER for most applications and
SCHED_FIFO for the threaded interrupts and a few others.
The tasks that are running during the test-case should be all
SCHED_OTHER.

> > Could you try if you can reproduce this with v7.3-rc7? This one does not
> > require any additional patches.
> > I'm not sure if this report would help the btrfs folks to recognize if
> > this is a solved problem or where the issue might be.
> 
> Trying a later kernel is not impossible, but it somewhat time
> consuming, I will have to strip a number of things from the build, 
> and Yocto doesn't make this particularly straightforward, and might
> even compromise the test. We will update the kernel 
> in due course, but you'll understand I'd prefer not to commit this
> time without some degree of confirmation here.  As things
> stand right now, it may be that we just run without RT, but it would
> be good to at least verify this, and have a record for 
> other people. 

Right. You could try just the bare-kernel and yocto's .config without
anything else. And then just replace the kernel (and modules) on the
target. If this procedure can reproduce the bug on the latest kernel
then it is still around. Otherwise it is either fixed or something
changed and it does not reproduce anymore.

> As for brtfs, yes that was my next follow up, I had been just about to
> do that before your reply. 

I'm not a btrfs guy myself so I kind tell if this gives people enough
clues to as what is going on.

> Regards. 

Sebastian

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

* Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
       [not found] ` <SJ0PR17MB4288FC2E7FFB577F5D6C6D9EBB9E2@SJ0PR17MB4288.namprd17.prod.outlook.com>
@ 2026-10-13 17:33   ` Naulls, Peter
  2026-10-14 14:23     ` Daniel Vacek
  2026-10-14 14:33     ` Daniel Vacek
  0 siblings, 2 replies; 7+ messages in thread
From: Naulls, Peter @ 2026-10-13 17:33 UTC (permalink / raw)
  To: linux-btrfs@vger.kernel.org

 
Originally posted to RT mailing list, see post and replies there:

https://lore.kernel.org/linux-rt-users/PH0PR17MB4277167A37B20340B231443FBB922@PH0PR17MB4277.namprd17.prod.outlook.com/T/#u

________________________________________
From: Naulls, Peter <PeterNaulls@eaton.com>
Sent: Friday, October 9, 2026 11:34 AM
To: linux-rt-users@vger.kernel.org <linux-rt-users@vger.kernel.org>
Subject: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
 
Long term kernel hacker, but very infrequent contributor. 

We are using the RT kernel patch on x86 under kernel 6.6.78-rt51. Specifically, this is the kernel from meta-intel in Yocto Scarthgap in the intel-kernel-rt recipe. 

It appears under some high load conditions, and especially triggered by calls to sync(), there is a live lock condition in the btrfs code. I used copilot for this analysis, with apologies due here where relevant. I'm familiar with kernel code, and I'm well aware how complex filesystem interactions can be. 

Here is the lock we observe:


sync (PID 52371)
  btrfs_commit_transaction+0xc48
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  btrfs_sync_fs
  sync_fs_one_sb
  ksys_sync

ordered-I/O completion workers
  join_transaction+0x2b
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  start_transaction
  btrfs_join_transaction
  btrfs_finish_one_ordered
  btrfs_work_helper

journal/fsync callers
  wait_current_trans+0x33
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  start_transaction
  btrfs_start_transaction
  btrfs_sync_file
  vfs_fsync_range
  fsync

btrfs-transaction thread
  transaction_kthread+0x76
    [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
  kthread


The processes are then not killable, indicting a kernel thread problem. 

This was largely found because our userspace code calls sync() excessively (being separately addressed), although that's not the proximate cause. We ended up writing shell script which writes blocks of data to a brtfs partition over several threads and also calls sync and were able to repeat it within 10s of seconds. It is not repeatable in the non-RT kernel.

To add:

I have been extensively through the later kernels in 6.6, and later series and have not found any direct fixe or references for this. I've also been through the latest RT changes and btrfs mailing lists/changes (and this post might be served better there) and cannot find any direct reference to this. The only close match is:

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=99da896614d17e8a84aeb2b2d464ac046cc8633d

This is in related code. I put this patch into our 6.6.78 kernel and it did not resolve the problem. 

With that in mind, I had copilot (again, apologies) have an attempt. It came up with this:

# Experimental mitigation for a suspected PREEMPT_RT Btrfs transaction-waiter
# livelock. wait_for_commit() can reselect a completed transaction that remains
# on trans_list after its waiters are woken. Skip completed entries while still
# waiting for older incomplete transactions. This is a diagnostic hypothesis,
# not a confirmed fix for the observed lockup.
# Review notes: the scan is O(n) under trans_lock. Completion state is published
# locklessly elsewhere; READ_ONCE provides a single load, not acquire ordering.
# A multi-hour run did not reproduce the issue, but the lock owner and root cause
# remain unknown.
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index e15e1855fa0a..0f05fabe451c 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -865,6 +865,7 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
                                     const enum btrfs_trans_state min_state)
 {
        struct btrfs_fs_info *fs_info = commit->fs_info;
+       struct btrfs_transaction *next;
        u64 transid = commit->transid;
        bool put = false;

@@ -893,10 +894,16 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
                 */

                spin_lock(&fs_info->trans_lock);
-               commit = list_first_entry_or_null(&fs_info->trans_list,
-                                                 struct btrfs_transaction,
-                                                 list);
-               if (!commit || commit->transid > transid) {
+               commit = NULL;
+               list_for_each_entry(next, &fs_info->trans_list, list) {
+                       if (next->transid > transid)
+                               break;
+                       if (READ_ONCE(next->state) == TRANS_STATE_COMPLETED)
+                               continue;
+                       commit = next;
+                       break;
+               }
+               if (!commit) {
                        spin_unlock(&fs_info->trans_lock);
                        break;
                }


Note the O(N) time here. To that end, this is very unlikely to be the correct fix, but I hope it highlights the core problem. I ran this patch for several hours with no apparent problem (versus seconds of a lockup in previous testing).

If there's a later kernel patch I've missed, or something else I ought to be looking at or test or need more info, please let me know.

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

* Re: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
  2026-10-13 17:33   ` Naulls, Peter
@ 2026-10-14 14:23     ` Daniel Vacek
  2026-10-14 14:33     ` Daniel Vacek
  1 sibling, 0 replies; 7+ messages in thread
From: Daniel Vacek @ 2026-10-14 14:23 UTC (permalink / raw)
  To: Naulls, Peter; +Cc: linux-btrfs@vger.kernel.org

On Tue, 13 Oct 2026 at 19:46, Naulls, Peter <PeterNaulls@eaton.com> wrote:
>
> Originally posted to RT mailing list, see post and replies there:
>
> https://lore.kernel.org/linux-rt-users/PH0PR17MB4277167A37B20340B231443FBB922@PH0PR17MB4277.namprd17.prod.outlook.com/T/#u
>
> ________________________________________
> From: Naulls, Peter <PeterNaulls@eaton.com>
> Sent: Friday, October 9, 2026 11:34 AM
> To: linux-rt-users@vger.kernel.org <linux-rt-users@vger.kernel.org>
> Subject: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
>
> Long term kernel hacker, but very infrequent contributor.
>
> We are using the RT kernel patch on x86 under kernel 6.6.78-rt51. Specifically, this is the kernel from meta-intel in Yocto Scarthgap in the intel-kernel-rt recipe.
>
> It appears under some high load conditions, and especially triggered by calls to sync(), there is a live lock condition in the btrfs code. I used copilot for this analysis, with apologies due here where relevant. I'm familiar with kernel code, and I'm well aware how complex filesystem interactions can be.
>
> Here is the lock we observe:
>
>
> sync (PID 52371)
>   btrfs_commit_transaction+0xc48
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   btrfs_sync_fs
>   sync_fs_one_sb
>   ksys_sync
>
> ordered-I/O completion workers
>   join_transaction+0x2b
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   start_transaction
>   btrfs_join_transaction
>   btrfs_finish_one_ordered
>   btrfs_work_helper
>
> journal/fsync callers
>   wait_current_trans+0x33
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   start_transaction
>   btrfs_start_transaction
>   btrfs_sync_file
>   vfs_fsync_range
>   fsync
>
> btrfs-transaction thread
>   transaction_kthread+0x76
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   kthread
>
>
> The processes are then not killable, indicting a kernel thread problem.
>
> This was largely found because our userspace code calls sync() excessively (being separately addressed), although that's not the proximate cause. We ended up writing shell script which writes blocks of data to a brtfs partition over several threads and also calls sync and were able to repeat it within 10s of seconds. It is not repeatable in the non-RT kernel.
>
> To add:
>
> I have been extensively through the later kernels in 6.6, and later series and have not found any direct fixe or references for this. I've also been through the latest RT changes and btrfs mailing lists/changes (and this post might be served better there) and cannot find any direct reference to this. The only close match is:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=99da896614d17e8a84aeb2b2d464ac046cc8633d
>
> This is in related code. I put this patch into our 6.6.78 kernel and it did not resolve the problem.
>
> With that in mind, I had copilot (again, apologies) have an attempt. It came up with this:
>
> # Experimental mitigation for a suspected PREEMPT_RT Btrfs transaction-waiter
> # livelock. wait_for_commit() can reselect a completed transaction that remains
> # on trans_list after its waiters are woken. Skip completed entries while still
> # waiting for older incomplete transactions. This is a diagnostic hypothesis,
> # not a confirmed fix for the observed lockup.
> # Review notes: the scan is O(n) under trans_lock. Completion state is published
> # locklessly elsewhere; READ_ONCE provides a single load, not acquire ordering.
> # A multi-hour run did not reproduce the issue, but the lock owner and root cause
> # remain unknown.

Right, the above does not explain why this only happens on RT.

Though the lock owner can be easily found using crash or drgn. One
could also expect it's task->sched_info.last_arrival timestamp would
be about close to those blocked tasks you found.

Would you mind sharing a vmcore (and (a link to) the debug symbols)?
Or eventualy the root access to the reproducer machine? (in case you
have an ephemeral VM)

I'll try to review the related code in the meantime.

--nX

> diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
> index e15e1855fa0a..0f05fabe451c 100644
> --- a/fs/btrfs/transaction.c
> +++ b/fs/btrfs/transaction.c
> @@ -865,6 +865,7 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
>                                      const enum btrfs_trans_state min_state)
>  {
>         struct btrfs_fs_info *fs_info = commit->fs_info;
> +       struct btrfs_transaction *next;
>         u64 transid = commit->transid;
>         bool put = false;
>
> @@ -893,10 +894,16 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
>                  */
>
>                 spin_lock(&fs_info->trans_lock);
> -               commit = list_first_entry_or_null(&fs_info->trans_list,
> -                                                 struct btrfs_transaction,
> -                                                 list);
> -               if (!commit || commit->transid > transid) {
> +               commit = NULL;
> +               list_for_each_entry(next, &fs_info->trans_list, list) {
> +                       if (next->transid > transid)
> +                               break;
> +                       if (READ_ONCE(next->state) == TRANS_STATE_COMPLETED)
> +                               continue;
> +                       commit = next;
> +                       break;
> +               }
> +               if (!commit) {
>                         spin_unlock(&fs_info->trans_lock);
>                         break;
>                 }
>
>
> Note the O(N) time here. To that end, this is very unlikely to be the correct fix, but I hope it highlights the core problem. I ran this patch for several hours with no apparent problem (versus seconds of a lockup in previous testing).
>
> If there's a later kernel patch I've missed, or something else I ought to be looking at or test or need more info, please let me know.
>

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

* Re: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
  2026-10-13 17:33   ` Naulls, Peter
  2026-10-14 14:23     ` Daniel Vacek
@ 2026-10-14 14:33     ` Daniel Vacek
  1 sibling, 0 replies; 7+ messages in thread
From: Daniel Vacek @ 2026-10-14 14:33 UTC (permalink / raw)
  To: Naulls, Peter; +Cc: linux-btrfs@vger.kernel.org

On Tue, 13 Oct 2026 at 19:46, Naulls, Peter <PeterNaulls@eaton.com> wrote:
>
> Originally posted to RT mailing list, see post and replies there:
>
> https://lore.kernel.org/linux-rt-users/PH0PR17MB4277167A37B20340B231443FBB922@PH0PR17MB4277.namprd17.prod.outlook.com/T/#u
>
> ________________________________________
> From: Naulls, Peter <PeterNaulls@eaton.com>
> Sent: Friday, October 9, 2026 11:34 AM
> To: linux-rt-users@vger.kernel.org <linux-rt-users@vger.kernel.org>
> Subject: Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78
>
> Long term kernel hacker, but very infrequent contributor.
>
> We are using the RT kernel patch on x86 under kernel 6.6.78-rt51. Specifically, this is the kernel from meta-intel in Yocto Scarthgap in the intel-kernel-rt recipe.
>
> It appears under some high load conditions, and especially triggered by calls to sync(), there is a live lock condition in the btrfs code. I used copilot for this analysis, with apologies due here where relevant. I'm familiar with kernel code, and I'm well aware how complex filesystem interactions can be.
>
> Here is the lock we observe:
>
>
> sync (PID 52371)
>   btrfs_commit_transaction+0xc48
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   btrfs_sync_fs
>   sync_fs_one_sb
>   ksys_sync
>
> ordered-I/O completion workers
>   join_transaction+0x2b
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   start_transaction
>   btrfs_join_transaction
>   btrfs_finish_one_ordered
>   btrfs_work_helper
>
> journal/fsync callers
>   wait_current_trans+0x33
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   start_transaction
>   btrfs_start_transaction
>   btrfs_sync_file
>   vfs_fsync_range
>   fsync
>
> btrfs-transaction thread
>   transaction_kthread+0x76
>     [return address immediately after rt_spin_lock(&fs_info->trans_lock)]
>   kthread

Neither of these seems to come from an interrupt. By any chance, have
you seen a "sleeping while atomic" error in dmesg?

--nX

> The processes are then not killable, indicting a kernel thread problem.
>
> This was largely found because our userspace code calls sync() excessively (being separately addressed), although that's not the proximate cause. We ended up writing shell script which writes blocks of data to a brtfs partition over several threads and also calls sync and were able to repeat it within 10s of seconds. It is not repeatable in the non-RT kernel.
>
> To add:
>
> I have been extensively through the later kernels in 6.6, and later series and have not found any direct fixe or references for this. I've also been through the latest RT changes and btrfs mailing lists/changes (and this post might be served better there) and cannot find any direct reference to this. The only close match is:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=99da896614d17e8a84aeb2b2d464ac046cc8633d
>
> This is in related code. I put this patch into our 6.6.78 kernel and it did not resolve the problem.
>
> With that in mind, I had copilot (again, apologies) have an attempt. It came up with this:
>
> # Experimental mitigation for a suspected PREEMPT_RT Btrfs transaction-waiter
> # livelock. wait_for_commit() can reselect a completed transaction that remains
> # on trans_list after its waiters are woken. Skip completed entries while still
> # waiting for older incomplete transactions. This is a diagnostic hypothesis,
> # not a confirmed fix for the observed lockup.
> # Review notes: the scan is O(n) under trans_lock. Completion state is published
> # locklessly elsewhere; READ_ONCE provides a single load, not acquire ordering.
> # A multi-hour run did not reproduce the issue, but the lock owner and root cause
> # remain unknown.
> diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
> index e15e1855fa0a..0f05fabe451c 100644
> --- a/fs/btrfs/transaction.c
> +++ b/fs/btrfs/transaction.c
> @@ -865,6 +865,7 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
>                                      const enum btrfs_trans_state min_state)
>  {
>         struct btrfs_fs_info *fs_info = commit->fs_info;
> +       struct btrfs_transaction *next;
>         u64 transid = commit->transid;
>         bool put = false;
>
> @@ -893,10 +894,16 @@ static noinline void wait_for_commit(struct btrfs_transaction *commit,
>                  */
>
>                 spin_lock(&fs_info->trans_lock);
> -               commit = list_first_entry_or_null(&fs_info->trans_list,
> -                                                 struct btrfs_transaction,
> -                                                 list);
> -               if (!commit || commit->transid > transid) {
> +               commit = NULL;
> +               list_for_each_entry(next, &fs_info->trans_list, list) {
> +                       if (next->transid > transid)
> +                               break;
> +                       if (READ_ONCE(next->state) == TRANS_STATE_COMPLETED)
> +                               continue;
> +                       commit = next;
> +                       break;
> +               }
> +               if (!commit) {
>                         spin_unlock(&fs_info->trans_lock);
>                         break;
>                 }
>
>
> Note the O(N) time here. To that end, this is very unlikely to be the correct fix, but I hope it highlights the core problem. I ran this patch for several hours with no apparent problem (versus seconds of a lockup in previous testing).
>
> If there's a later kernel patch I've missed, or something else I ought to be looking at or test or need more info, please let me know.
>

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

end of thread, other threads:[~2026-10-14 14:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-09 15:34 Btrfs PREEMPT_RT transaction-waiter livelock: experimental mitigation in kernel 6.6.78 Naulls, Peter
2026-10-13 14:41 ` Sebastian Andrzej Siewior
2026-10-13 15:29   ` [EXTERNAL] " Naulls, Peter
2026-10-13 15:52     ` Sebastian Andrzej Siewior
     [not found] ` <SJ0PR17MB4288FC2E7FFB577F5D6C6D9EBB9E2@SJ0PR17MB4288.namprd17.prod.outlook.com>
2026-10-13 17:33   ` Naulls, Peter
2026-10-14 14:23     ` Daniel Vacek
2026-10-14 14:33     ` Daniel Vacek

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.