From: Andreas Gruenbacher agruenba@redhat.com
[ Upstream commit 8a157e0a0aa5143b5d94201508c0ca1bb8cfb941 ]
In gfs2_chain_bio(), the call to bio_chain() has its arguments swapped. The result is leaked bios and incorrect synchronization (only the last bio will actually be waited for). This code is only used during mount and filesystem thaw, so the bug normally won't be noticeable.
Reported-by: Stephen Zhang starzhangzsd@gmail.com Signed-off-by: Andreas Gruenbacher agruenba@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
Now I understand the bug clearly. The `bio_chain()` signature is: ```c void bio_chain(struct bio *bio, struct bio *parent) ```
Where: - `bio` - the target bio being submitted - `parent` - the bio whose completion will be delayed until both complete
**The Bug:** In `gfs2_chain_bio()`: ```c new->bi_iter.bi_sector = bio_end_sector(prev); bio_chain(new, prev); // WRONG: arguments swapped submit_bio(prev); return new; ```
The function allocates `new`, chains with `prev`, submits `prev`, and returns `new`. The intention is that `new` accumulates all completions - callers wait on `new`.
With the **wrong order** `bio_chain(new, prev)`: - `new`'s completion increments `prev`'s remaining count - But `prev` is submitted immediately and freed after completion - Result: **leaked bios** (new never freed properly) and **incorrect synchronization** (waiting on `new` doesn't work correctly)
With the **correct order** `bio_chain(prev, new)`: - `prev`'s completion increments `new`'s remaining count - Waiting on `new` correctly waits for all chained bios
## 3. CLASSIFICATION
- **Type:** Bug fix - logic error (swapped arguments) - **Impact:** Memory leaks and incorrect I/O synchronization in GFS2 - **Not:** Feature addition, refactoring, or cleanup
## 4. SCOPE AND RISK ASSESSMENT
- **Lines changed:** 1 line - **Files touched:** 1 file - **Complexity:** Trivial - argument swap - **Risk:** Extremely low - this is the obviously correct fix
The fix is minimal, self-contained, and the correct argument order is unambiguous from the API documentation.
## 5. USER IMPACT
- **Affected users:** GFS2 users (enterprise/cluster environments) - **Trigger conditions:** Mount and filesystem thaw operations - **Severity:** - Bio leaks (memory exhaustion over time) - Incorrect synchronization could lead to data consistency issues during mount/thaw
While the maintainer notes "normally won't be noticeable," in production cluster environments, bio leaks during repeated mount/umount cycles could be problematic, and synchronization bugs in filesystem code are inherently risky.
## 6. STABILITY INDICATORS
- Reported-by tag (issue was identified) - Signed by GFS2 maintainer (Andreas Gruenbacher) - Trivially correct fix - no ambiguity about the right solution
## 7. DEPENDENCY CHECK
This is a standalone fix with no dependencies. The `bio_chain()` API is stable and has existed for years.
## CONCLUSION
**Meets stable criteria:** - ✅ Obviously correct - clear API misuse with documented correct usage - ✅ Fixes real bug - bio leaks and incorrect synchronization - ✅ Small and contained - single one-line change - ✅ No new features - ✅ Risk is minimal
**Minor concerns:** - No explicit `Cc: stable@vger.kernel.org` tag (maintainer didn't request backport) - No `Fixes:` tag identifying affected versions - Impact described as "normally won't be noticeable"
Despite the lack of explicit stable tags, this is a clear bug fix to filesystem code. Bio leaks and synchronization issues in filesystem operations are exactly the type of bugs stable trees should fix. The change is trivial, obviously correct, and carries essentially zero risk of regression.
**YES**
fs/gfs2/lops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 9c8c305a75c46..914d03f6c4e82 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -487,7 +487,7 @@ static struct bio *gfs2_chain_bio(struct bio *prev, unsigned int nr_iovecs) new = bio_alloc(prev->bi_bdev, nr_iovecs, prev->bi_opf, GFP_NOIO); bio_clone_blkg_association(new, prev); new->bi_iter.bi_sector = bio_end_sector(prev); - bio_chain(new, prev); + bio_chain(prev, new); submit_bio(prev); return new; }