Re: [PATCH] ocfs2: fix chunk number of the first chunk in a local quota file
From: Joseph Qi
Date: Tue Sep 15 2026 - 05:50:05 EST
On 9/14/26 11:49 AM, Jiaming Zhang wrote:
> The local quota file in OCFS2 is divided into chunks, and each chunk
> begins with a header block holding a bitmap of the quota entries that
> chunk has handed out. Chunks are numbered from zero, and that number is
> used to convert the file offset of an entry back into a bit position in
> the bitmap. ocfs2_local_quota_add_chunk() appends a new chunk to the
> in-memory list and numbers it one past the chunk that was last:
>
> list_add_tail(&chunk->qc_chunk, &oinfo->dqi_chunk);
> chunk->qc_num = list_entry(chunk->qc_chunk.prev,
> struct ocfs2_quota_chunk,
> qc_chunk)->qc_num + 1;
>
> The predecessor is looked up after the new chunk is added to the list,
> so if the list was empty, the prev pointer is the list head itself. The
> head is the dqi_chunk member of struct ocfs2_mem_dqinfo and is not a
> chunk, so reading qc_num through it lands 16 bytes past the start of the
> head, on the dqi_gqinode pointer that follows it. The first chunk of
> the file is then numbered with the lower half of a kernel pointer
> instead of 0.
>
> The list is empty when the local quota file header claims the file has
> no chunks. ocfs2_local_read_info() takes dqi_chunks from that header
> without validating it, so an image with dqi_chunks == 0 takes this path
> when the first quota entry is allocated.
>
> ocfs2_create_local_dquot() turns the bad number into a file offset with
> ol_dqblk_off(), which shifts a 32-bit block number left by the block
> size bits, so the top bits of such a large block number are lost.
> ocfs2_local_release_dquot() turns the offset back into a bit index with
> ol_dqblk_chunk_off(), using the full chunk number, so the lost bits push
> that index far outside the bitmap, and clearing it corrupts unrelated
> memory.
>
> Compute the chunk number before putting the chunk on the list, and use 0
> when the list is empty.
>
> Fixes: 9e33d69f553a ("ocfs2: Implementation of local and global quota file handling")
> Closes: https://lore.kernel.org/lkml/CANypQFZ05tpth0Xc33gmP6jgPnkY4VuezyHcsajV-SqCsmN_gg@xxxxxxxxxxxxxx/
> Cc: stable@xxxxxxxxxxxxxxx
> Assisted-by: Claude Code:claude-opus-5
> Signed-off-by: Jiaming Zhang <r772577952@xxxxxxxxx>
Reviewed-by: Joseph Qi <joseph.qi@xxxxxxxxxxxxxxxxx>
> ---
> fs/ocfs2/quota_local.c | 9 ++++++---
> 1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
> index f55810c59b1b..d351cda9211f 100644
> --- a/fs/ocfs2/quota_local.c
> +++ b/fs/ocfs2/quota_local.c
> @@ -1071,10 +1071,13 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
> goto out;
> }
>
> + if (list_empty(&oinfo->dqi_chunk))
> + chunk->qc_num = 0;
> + else
> + chunk->qc_num = list_entry(oinfo->dqi_chunk.prev,
> + struct ocfs2_quota_chunk,
> + qc_chunk)->qc_num + 1;
> list_add_tail(&chunk->qc_chunk, &oinfo->dqi_chunk);
> - chunk->qc_num = list_entry(chunk->qc_chunk.prev,
> - struct ocfs2_quota_chunk,
> - qc_chunk)->qc_num + 1;
> chunk->qc_headerbh = bh;
> *offset = 0;
> return chunk;