[PATCH AUTOSEL 6.19-5.10] jfs: nlink overflow in jfs_rename

Sasha Levin
2026-02-14T21:27:13Z

From: Jori Koolstra <jkoolstra@xs4all.nl>

[ Upstream commit 9218dc26fd922b09858ecd3666ed57dfd8098da8 ]

If nlink is maximal for a directory (-1) and inside that directory you
perform a rename for some child directory (not moving from the parent),
then the nlink of the first directory is first incremented and later
decremented. Normally this is fine, but when nlink = -1 this causes a
wrap around to 0, and then drop_nlink issues a warning.

After applying the patch syzbot no longer issues any warnings. I also
ran some basic fs tests to look for any regressions.

Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
Reported-by: syzbot+9131ddfd7870623b719f@syzkaller.appspotmail.com
Closes: https://syzbot.org/bug?extid=9131ddfd7870623b719f
Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis of jfs: nlink overflow in jfs_rename

### 1. Commit Message Analysis

The commit message is clear and well-structured:
- **Problem**: When a directory has maximum nlink (`-1` / `UINT_MAX`),
performing a rename of a child directory within the same parent causes
nlink to wrap around: first incremented (wraps to 0), then decremented
via `drop_nlink()` which triggers a kernel WARNING because nlink is
already 0.
- **Reporter**: syzbot (Google's kernel fuzzer) — a strong indicator of
a real, reproducible bug.
- **Testing**: Author confirms syzbot warning is resolved and ran basic
fs regression tests.
- **Maintainer sign-off**: Dave Kleikamp (JFS maintainer) signed off.

### 2. Code Change Analysis

The fix is in `fs/jfs/namei.c` in the `jfs_rename()` function. Two
changes:

**Change 1** (line ~1231):
```c
- if (S_ISDIR(old_ip->i_mode))
+ if (S_ISDIR(old_ip->i_mode) && old_dir != new_dir)
inc_nlink(new_dir);
```
When renaming a directory within the **same parent** (`old_dir ==
new_dir`), there's no need to increment nlink on the new directory
because the directory isn't gaining a new subdirectory — the
subdirectory is just being renamed in place. The `inc_nlink` should only
happen when moving a directory to a **different** parent.

**Change 2** (lines ~1245-1247):
```c
- drop_nlink(old_dir);
+ if (new_ip || old_dir != new_dir)
+ drop_nlink(old_dir);
```
Similarly, `drop_nlink` on `old_dir` should only happen when the
directory is actually losing a subdirectory (either it's being moved to
a different parent, or it's replacing an existing entry `new_ip`). When
renaming within the same directory and not replacing anything, nlink
shouldn't change.

### 3. Bug Mechanism

The bug is an nlink integer overflow/underflow:
1. Directory has nlink = `UINT_MAX` (maximum value)
2. A child directory rename within the same parent triggers
`inc_nlink()` → nlink wraps to 0
3. Then `drop_nlink()` is called on nlink=0, which triggers a `WARN_ON`
in the VFS layer
4. This causes a kernel WARNING — a clear stability issue

The fix is logically correct: when renaming within the same directory,
nlink shouldn't be touched at all since the number of subdirectories
hasn't changed.

### 4. Classification

- **Bug fix**: YES — fixes an nlink overflow/underflow that triggers
kernel warnings
- **Syzbot-reported**: YES — reproducible fuzzer-found bug
- **Security relevance**: MEDIUM — nlink corruption could potentially be
exploited, and triggering kernel warnings is itself a stability
concern

### 5. Scope and Risk Assessment

- **Lines changed**: ~6 lines of actual logic change (very small)
- **Files touched**: 1 file (`fs/jfs/namei.c`)
- **Subsystem**: JFS filesystem — mature, stable filesystem
- **Risk**: LOW — the conditions added (`old_dir != new_dir` and
`new_ip`) are standard checks already used elsewhere in the same
function. The logic is straightforward: don't modify nlink when the
directory count isn't actually changing.
- **Regression risk**: MINIMAL — this makes JFS consistent with how
other filesystems handle same-directory renames

### 6. Stable Kernel Criteria Check

- **Obviously correct and tested**: YES — logic is clear, tested by
author, verified by syzbot
- **Fixes a real bug**: YES — kernel WARNING trigger, nlink corruption
- **Important issue**: YES — kernel WARNING, potential filesystem
metadata corruption
- **Small and contained**: YES — 6 lines in one file
- **No new features**: Correct — pure bug fix
- **No new APIs**: Correct

### 7. Dependencies

The fix is self-contained. It modifies conditions around existing
`inc_nlink()` and `drop_nlink()` calls. No dependency on other commits.
The affected code (`jfs_rename`) has been stable for years and exists in
all stable trees that include JFS.

### 8. User Impact

JFS users who encounter the maximum nlink scenario (which syzbot can
trigger) will see kernel warnings. While the scenario requires nlink to
be at maximum, this is a correctness issue in filesystem metadata
handling. Filesystem bugs are always high-priority for stable because
they can lead to data corruption or loss.

### Conclusion

This is a textbook stable backport candidate: a small, surgical fix to a
syzbot-reported bug in filesystem code, fixing an nlink overflow that
triggers kernel warnings. It's obviously correct, well-tested,
maintainer-approved, and carries minimal regression risk.

**YES**

fs/jfs/namei.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 65a218eba8faf..7879c049632b3 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1228,7 +1228,7 @@ static int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
jfs_err("jfs_rename: dtInsert returned -EIO");
goto out_tx;
}
- if (S_ISDIR(old_ip->i_mode))
+ if (S_ISDIR(old_ip->i_mode) && old_dir != new_dir)
inc_nlink(new_dir);
}
/*
@@ -1244,7 +1244,9 @@ static int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
goto out_tx;
}
if (S_ISDIR(old_ip->i_mode)) {
- drop_nlink(old_dir);
+ if (new_ip || old_dir != new_dir)
+ drop_nlink(old_dir);
+
if (old_dir != new_dir) {
/*
* Change inode number of parent for moved directory
--
2.51.0