fs/ocfs2/suballoc.c | 7 +++++++ 1 file changed, 7 insertions(+)
syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the
`cl_next_free_rec` field of the allocation chain list is 0, triggring the
BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
To fix this, `cl_next_free_rec` is checked inside the caller of
ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is
equal to 0, ocfs2_error() is called, to log the corruption and force the
filesystem into read-only mode, to prevent further damage.
Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72
Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
Cc: stable@vger.kernel.org
Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com>
---
fs/ocfs2/suballoc.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index 6ac4dcd54588..84bb2d11c2aa 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -1993,6 +1993,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
+ if (le16_to_cpu(cl->cl_next_free_rec) == 0) {
+ status = ocfs2_error(ac->ac_inode->i_sb,
+ "Chain allocator dinode %llu has 0 chains\n",
+ (unsigned long long)le64_to_cpu(fe->i_blkno));
+ goto bail;
+ }
+
victim = ocfs2_find_victim_chain(cl);
ac->ac_chain = victim;
base-commit: 939f15e640f193616691d3bcde0089760e75b0d3
--
2.34.1
On 2025/11/30 18:46, Prithvi Tambewagh wrote:
> syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the
> `cl_next_free_rec` field of the allocation chain list is 0, triggring the
> BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
>
> To fix this, `cl_next_free_rec` is checked inside the caller of
> ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is
> equal to 0, ocfs2_error() is called, to log the corruption and force the
> filesystem into read-only mode, to prevent further damage.
>
> Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72
> Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
> Cc: stable@vger.kernel.org
> Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com>
> ---
> fs/ocfs2/suballoc.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
> index 6ac4dcd54588..84bb2d11c2aa 100644
> --- a/fs/ocfs2/suballoc.c
> +++ b/fs/ocfs2/suballoc.c
> @@ -1993,6 +1993,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
>
> cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
>
This blank line can be eliminated.
> + if (le16_to_cpu(cl->cl_next_free_rec) == 0) {
Better to add the upper limit check as well. e.g.
!le16_to_cpu(cl->cl_next_free_rec) ||
le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)
Thanks,
Joseph
> + status = ocfs2_error(ac->ac_inode->i_sb,
> + "Chain allocator dinode %llu has 0 chains\n",
> + (unsigned long long)le64_to_cpu(fe->i_blkno));
> + goto bail;
> + }
> +
> victim = ocfs2_find_victim_chain(cl);
> ac->ac_chain = victim;
>
>
> base-commit: 939f15e640f193616691d3bcde0089760e75b0d3
On Mon, Dec 01, 2025 at 10:51:49AM +0800, Joseph Qi wrote:
>
>
>On 2025/11/30 18:46, Prithvi Tambewagh wrote:
>> syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the
>> `cl_next_free_rec` field of the allocation chain list is 0, triggring the
>> BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
>>
>> To fix this, `cl_next_free_rec` is checked inside the caller of
>> ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is
>> equal to 0, ocfs2_error() is called, to log the corruption and force the
>> filesystem into read-only mode, to prevent further damage.
>>
>> Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>> Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72
>> Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com>
>> ---
>> fs/ocfs2/suballoc.c | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
>> index 6ac4dcd54588..84bb2d11c2aa 100644
>> --- a/fs/ocfs2/suballoc.c
>> +++ b/fs/ocfs2/suballoc.c
>> @@ -1993,6 +1993,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
>>
>> cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
>>
>
>This blank line can be eliminated.
>
>> + if (le16_to_cpu(cl->cl_next_free_rec) == 0) {
>
>Better to add the upper limit check as well. e.g.
>
>!le16_to_cpu(cl->cl_next_free_rec) ||
>le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)
Hello Joseph,
I went through the code in fs/ocfs2/suballoc.c, like this function
static inline u16 ocfs2_find_smallest_chain(struct ocfs2_chain_list *cl)
{
u16 curr, best;
best = curr = 0;
while (curr < le16_to_cpu(cl->cl_count)) {
if (le32_to_cpu(cl->cl_recs[best].c_total) >
le32_to_cpu(cl->cl_recs[curr].c_total))
best = curr;
curr++;
}
return best;
}
and in function ocfs2_block_group_alloc() these lines
if (le16_to_cpu(cl->cl_next_free_rec) < le16_to_cpu(cl->cl_count))
le16_add_cpu(&cl->cl_next_free_rec, 1);
and observed that according to the architecture of ocfs2, the chain list is
in the form of 0-indexed array. In that case, the change you suggested for
upper limit, could be re-written as
le16_to_cpu(cl->cl_next_free_rec) >= le16_to_cpu(cl->cl_count)
since value of cl->cl_next_free_rec greater than or equal to cl->cl_count
will indicate that there are no available chains. Can you please review this?
Thank you,
Prithvi
>
>Thanks,
>Joseph
>
>> + status = ocfs2_error(ac->ac_inode->i_sb,
>> + "Chain allocator dinode %llu has 0 chains\n",
>> + (unsigned long long)le64_to_cpu(fe->i_blkno));
>> + goto bail;
>> + }
>> +
>> victim = ocfs2_find_victim_chain(cl);
>> ac->ac_chain = victim;
>>
>>
>> base-commit: 939f15e640f193616691d3bcde0089760e75b0d3
>
On 2025/12/1 14:24, Prithvi Tambewagh wrote:
> On Mon, Dec 01, 2025 at 10:51:49AM +0800, Joseph Qi wrote:
>>
>>
>> On 2025/11/30 18:46, Prithvi Tambewagh wrote:
>>> syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the
>>> `cl_next_free_rec` field of the allocation chain list is 0, triggring the
>>> BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
>>>
>>> To fix this, `cl_next_free_rec` is checked inside the caller of
>>> ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is
>>> equal to 0, ocfs2_error() is called, to log the corruption and force the
>>> filesystem into read-only mode, to prevent further damage.
>>>
>>> Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>>> Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72
>>> Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>>> Cc: stable@vger.kernel.org
>>> Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com>
>>> ---
>>> fs/ocfs2/suballoc.c | 7 +++++++
>>> 1 file changed, 7 insertions(+)
>>>
>>> diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
>>> index 6ac4dcd54588..84bb2d11c2aa 100644
>>> --- a/fs/ocfs2/suballoc.c
>>> +++ b/fs/ocfs2/suballoc.c
>>> @@ -1993,6 +1993,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
>>>
>>> cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
>>>
>>
>> This blank line can be eliminated.
>>
>>> + if (le16_to_cpu(cl->cl_next_free_rec) == 0) {
>>
>> Better to add the upper limit check as well. e.g.
>>
>> !le16_to_cpu(cl->cl_next_free_rec) ||
>> le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)
>
> Hello Joseph,
>
> I went through the code in fs/ocfs2/suballoc.c, like this function
> static inline u16 ocfs2_find_smallest_chain(struct ocfs2_chain_list *cl)
> {
> u16 curr, best;
>
> best = curr = 0;
> while (curr < le16_to_cpu(cl->cl_count)) {
> if (le32_to_cpu(cl->cl_recs[best].c_total) >
> le32_to_cpu(cl->cl_recs[curr].c_total))
> best = curr;
> curr++;
> }
> return best;
> }
>
> and in function ocfs2_block_group_alloc() these lines
> if (le16_to_cpu(cl->cl_next_free_rec) < le16_to_cpu(cl->cl_count))
> le16_add_cpu(&cl->cl_next_free_rec, 1);
>
After this, cl_next_free_rec may equal to cl_count.
> and observed that according to the architecture of ocfs2, the chain list is in the form of 0-indexed array. In that case, the change you suggested for upper limit, could be re-written as
> le16_to_cpu(cl->cl_next_free_rec) >= le16_to_cpu(cl->cl_count)
>
> since value of cl->cl_next_free_rec greater than or equal to cl->cl_count will indicate that there are no available chains. Can you please review this?
>
Yes, it's full. But 'cl_next_free_rec == cl_count' is a designed behavior, see mkfs or fsck.
Joseph
On Mon, Dec 01, 2025 at 03:07:56PM +0800, Joseph Qi wrote:
>
>
>On 2025/12/1 14:24, Prithvi Tambewagh wrote:
>> On Mon, Dec 01, 2025 at 10:51:49AM +0800, Joseph Qi wrote:
>>>
>>>
>>> On 2025/11/30 18:46, Prithvi Tambewagh wrote:
>>>> syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the
>>>> `cl_next_free_rec` field of the allocation chain list is 0, triggring the
>>>> BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
>>>>
>>>> To fix this, `cl_next_free_rec` is checked inside the caller of
>>>> ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is
>>>> equal to 0, ocfs2_error() is called, to log the corruption and force the
>>>> filesystem into read-only mode, to prevent further damage.
>>>>
>>>> Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>>>> Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72
>>>> Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>>>> Cc: stable@vger.kernel.org
>>>> Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com>
>>>> ---
>>>> fs/ocfs2/suballoc.c | 7 +++++++
>>>> 1 file changed, 7 insertions(+)
>>>>
>>>> diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
>>>> index 6ac4dcd54588..84bb2d11c2aa 100644
>>>> --- a/fs/ocfs2/suballoc.c
>>>> +++ b/fs/ocfs2/suballoc.c
>>>> @@ -1993,6 +1993,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
>>>>
>>>> cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
>>>>
>>>
>>> This blank line can be eliminated.
>>>
>>>> + if (le16_to_cpu(cl->cl_next_free_rec) == 0) {
>>>
>>> Better to add the upper limit check as well. e.g.
>>>
>>> !le16_to_cpu(cl->cl_next_free_rec) ||
>>> le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)
>>
>> Hello Joseph,
>>
>> I went through the code in fs/ocfs2/suballoc.c, like this function
>> static inline u16 ocfs2_find_smallest_chain(struct ocfs2_chain_list *cl)
>> {
>> u16 curr, best;
>>
>> best = curr = 0;
>> while (curr < le16_to_cpu(cl->cl_count)) {
>> if (le32_to_cpu(cl->cl_recs[best].c_total) >
>> le32_to_cpu(cl->cl_recs[curr].c_total))
>> best = curr;
>> curr++;
>> }
>> return best;
>> }
>>
>> and in function ocfs2_block_group_alloc() these lines
>> if (le16_to_cpu(cl->cl_next_free_rec) < le16_to_cpu(cl->cl_count))
>> le16_add_cpu(&cl->cl_next_free_rec, 1);
>>
>After this, cl_next_free_rec may equal to cl_count.
>
>
>> and observed that according to the architecture of ocfs2, the chain list is in the form of 0-indexed array. In that case, the change you suggested for upper limit, could be re-written as
>> le16_to_cpu(cl->cl_next_free_rec) >= le16_to_cpu(cl->cl_count)
>>
>> since value of cl->cl_next_free_rec greater than or equal to cl->cl_count will indicate that there are no available chains. Can you please review this?
>>
>Yes, it's full. But 'cl_next_free_rec == cl_count' is a designed behavior, see mkfs or fsck.
I get it. We are trying to catch a state of disk corruption, so your
suggestion
le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)
fits best here. Thanks...I will make v2 for the patch.
Best Reards,
Prithvi
>
>Joseph
>
On Mon, Dec 01, 2025 at 10:51:49AM +0800, Joseph Qi wrote:
>
>
>On 2025/11/30 18:46, Prithvi Tambewagh wrote:
>> syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the
>> `cl_next_free_rec` field of the allocation chain list is 0, triggring the
>> BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
>>
>> To fix this, `cl_next_free_rec` is checked inside the caller of
>> ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is
>> equal to 0, ocfs2_error() is called, to log the corruption and force the
>> filesystem into read-only mode, to prevent further damage.
>>
>> Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>> Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72
>> Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com>
>> ---
>> fs/ocfs2/suballoc.c | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
>> index 6ac4dcd54588..84bb2d11c2aa 100644
>> --- a/fs/ocfs2/suballoc.c
>> +++ b/fs/ocfs2/suballoc.c
>> @@ -1993,6 +1993,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
>>
>> cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
>>
>
>This blank line can be eliminated.
>
>> + if (le16_to_cpu(cl->cl_next_free_rec) == 0) {
>
>Better to add the upper limit check as well. e.g.
>
>!le16_to_cpu(cl->cl_next_free_rec) ||
>le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)
>
>Thanks,
>Joseph
>
>> + status = ocfs2_error(ac->ac_inode->i_sb,
>> + "Chain allocator dinode %llu has 0 chains\n",
>> + (unsigned long long)le64_to_cpu(fe->i_blkno));
>> + goto bail;
>> + }
>> +
>> victim = ocfs2_find_victim_chain(cl);
>> ac->ac_chain = victim;
>>
>>
>> base-commit: 939f15e640f193616691d3bcde0089760e75b0d3
>
Hello Joseph,
Thanks for the feedback! I will make the changes in the patch. I wanted
to confirm that the new patch should be sent as v2 on this same thread,
along with the change log since v1, right?
Thanks,
Prithvi
On 2025/12/1 13:50, Prithvi Tambewagh wrote:
> On Mon, Dec 01, 2025 at 10:51:49AM +0800, Joseph Qi wrote:
>>
>>
>> On 2025/11/30 18:46, Prithvi Tambewagh wrote:
>>> syzbot reported a kernel BUG in ocfs2_find_victim_chain() because the
>>> `cl_next_free_rec` field of the allocation chain list is 0, triggring the
>>> BUG_ON(!cl->cl_next_free_rec) condition and panicking the kernel.
>>>
>>> To fix this, `cl_next_free_rec` is checked inside the caller of
>>> ocfs2_find_victim_chain() i.e. ocfs2_claim_suballoc_bits() and if it is
>>> equal to 0, ocfs2_error() is called, to log the corruption and force the
>>> filesystem into read-only mode, to prevent further damage.
>>>
>>> Reported-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>>> Closes: https://syzkaller.appspot.com/bug?extid=96d38c6e1655c1420a72
>>> Tested-by: syzbot+96d38c6e1655c1420a72@syzkaller.appspotmail.com
>>> Cc: stable@vger.kernel.org
>>> Signed-off-by: Prithvi Tambewagh <activprithvi@gmail.com>
>>> ---
>>> fs/ocfs2/suballoc.c | 7 +++++++
>>> 1 file changed, 7 insertions(+)
>>>
>>> diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
>>> index 6ac4dcd54588..84bb2d11c2aa 100644
>>> --- a/fs/ocfs2/suballoc.c
>>> +++ b/fs/ocfs2/suballoc.c
>>> @@ -1993,6 +1993,13 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac,
>>>
>>> cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
>>>
>>
>> This blank line can be eliminated.
>>
>>> + if (le16_to_cpu(cl->cl_next_free_rec) == 0) {
>>
>> Better to add the upper limit check as well. e.g.
>>
>> !le16_to_cpu(cl->cl_next_free_rec) ||
>> le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)
>>
>> Thanks,
>> Joseph
>>
>>> + status = ocfs2_error(ac->ac_inode->i_sb,
>>> + "Chain allocator dinode %llu has 0 chains\n",
>>> + (unsigned long long)le64_to_cpu(fe->i_blkno));
>>> + goto bail;
>>> + }
>>> +
>>> victim = ocfs2_find_victim_chain(cl);
>>> ac->ac_chain = victim;
>>>
>>>
>>> base-commit: 939f15e640f193616691d3bcde0089760e75b0d3
>>
>
> Hello Joseph,
>
> Thanks for the feedback! I will make the changes in the patch. I wanted to confirm that the new patch should be sent as v2 on this same thread, along with the change log since v1, right?
>
No need on the same thread, just v2 with the change log since v1 is enough.
Joseph
© 2016 - 2025 Red Hat, Inc.