Linux Btrfs filesystem development
 help / color / mirror / Atom feed
From: Dan Carpenter <error27@gmail.com>
To: Nikolay Borisov <nborisov@suse.com>
Cc: linux-btrfs@vger.kernel.org
Subject: [bug report] btrfs: refactor __btrfs_run_delayed_refs loop
Date: Thu, 21 May 2026 15:53:25 +0300	[thread overview]
Message-ID: <ag8ARRwykv8bpJ87@stanley.mountain> (raw)

[ 8 year old code and no one has complained...  It's surprising no
  one has hit this in real life. - dan ]

Hello Nikolay Borisov,

Commit 0110a4c43451 ("btrfs: refactor __btrfs_run_delayed_refs loop")
from Aug 15, 2018 (linux-next), leads to the following Smatch static
checker warning:

	fs/btrfs/extent-tree.c:2131 __btrfs_run_delayed_refs()
	error: 'locked_ref' dereferencing possible ERR_PTR()

fs/btrfs/extent-tree.c
    2084 static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
    2085                                              u64 min_bytes)
    2086 {
    2087         struct btrfs_fs_info *fs_info = trans->fs_info;
    2088         struct btrfs_delayed_ref_root *delayed_refs;
    2089         struct btrfs_delayed_ref_head *locked_ref = NULL;
    2090         int ret;
    2091         unsigned long count = 0;
    2092         unsigned long max_count = 0;
    2093         u64 bytes_processed = 0;
    2094 
    2095         delayed_refs = &trans->transaction->delayed_refs;
    2096         if (min_bytes == 0) {
    2097                 /*
    2098                  * We may be subject to a harmless race if some task is
    2099                  * concurrently adding or removing a delayed ref, so silence
    2100                  * KCSAN and similar tools.
    2101                  */
    2102                 max_count = data_race(delayed_refs->num_heads_ready);
    2103                 min_bytes = U64_MAX;
    2104         }
    2105 
    2106         do {
    2107                 if (!locked_ref) {
    2108                         locked_ref = btrfs_select_ref_head(fs_info, delayed_refs);
    2109                         if (IS_ERR_OR_NULL(locked_ref)) {
    2110                                 if (PTR_ERR(locked_ref) == -EAGAIN) {
    2111                                         continue;

In the old we set "locked_ref = NULL" on this path and I think we
probably should restore that line.  Now it looks like a crash.

    2112                                 } else {
    2113                                         break;
    2114                                 }
    2115                         }
    2116                         count++;
    2117                 }
    2118                 /*
    2119                  * We need to try and merge add/drops of the same ref since we
    2120                  * can run into issues with relocate dropping the implicit ref
    2121                  * and then it being added back again before the drop can
    2122                  * finish.  If we merged anything we need to re-loop so we can
    2123                  * get a good ref.
    2124                  * Or we can get node references of the same type that weren't
    2125                  * merged when created due to bumps in the tree mod seq, and
    2126                  * we need to merge them to prevent adding an inline extent
    2127                  * backref before dropping it (triggering a BUG_ON at
    2128                  * insert_inline_extent_backref()).
    2129                  */
    2130                 spin_lock(&locked_ref->lock);
                                    ^^^^^^^^^^^^^^^^
On the next iteration &locked_ref will be ERR_PTR(-EAGAIN).

--> 2131                 btrfs_merge_delayed_refs(fs_info, delayed_refs, locked_ref);
    2132 
    2133                 ret = btrfs_run_delayed_refs_for_head(trans, locked_ref, &bytes_processed);
    2134                 if (ret < 0 && ret != -EAGAIN) {
    2135                         /*
    2136                          * Error, btrfs_run_delayed_refs_for_head already
    2137                          * unlocked everything so just bail out
    2138                          */
    2139                         return ret;
    2140                 } else if (!ret) {
    2141                         /*
    2142                          * Success, perform the usual cleanup of a processed
    2143                          * head
    2144                          */
    2145                         ret = cleanup_ref_head(trans, locked_ref, &bytes_processed);
    2146                         if (ret > 0 ) {
    2147                                 /* We dropped our lock, we need to loop. */
    2148                                 ret = 0;
    2149                                 continue;
    2150                         } else if (ret) {
    2151                                 return ret;
    2152                         }
    2153                 }
    2154 
    2155                 /*
    2156                  * Either success case or btrfs_run_delayed_refs_for_head
    2157                  * returned -EAGAIN, meaning we need to select another head
    2158                  */
    2159 
    2160                 locked_ref = NULL;
    2161                 cond_resched();
    2162         } while ((min_bytes != U64_MAX && bytes_processed < min_bytes) ||
    2163                  (max_count > 0 && count < max_count) ||
    2164                  locked_ref);
                          ^^^^^^^^^^
We continue down to here and loop back since locked_ref is -EAGAIN.

    2165 
    2166         return 0;
    2167 }

This email is a free service from the Smatch-CI project [smatch.sf.net].

regards,
dan carpenter

             reply	other threads:[~2026-05-21 12:53 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-21 12:53 Dan Carpenter [this message]
2026-05-21 14:44 ` [bug report] btrfs: refactor __btrfs_run_delayed_refs loop Filipe Manana

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ag8ARRwykv8bpJ87@stanley.mountain \
    --to=error27@gmail.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=nborisov@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox