Skip to content

Hold transaction in scoutfs_quota_mod_rule to prevent alloc corruption.#297

Open
aversecat wants to merge 1 commit intomainfrom
auke/quota_mod_trans_hold
Open

Hold transaction in scoutfs_quota_mod_rule to prevent alloc corruption.#297
aversecat wants to merge 1 commit intomainfrom
auke/quota_mod_trans_hold

Conversation

@aversecat
Copy link
Copy Markdown
Contributor

scoutfs_quota_mod_rule calls scoutfs_item_create/delete which use the transaction allocator but it never held it. Without the hold, a concurrent transaction commit can call scoutfs_alloc_init to reinitialize the allocator while dirty_alloc_blocks is in the middle of setting up the freed list block. This overwrites alloc->freed with the server's fresh (empty) state, causing a blkno mismatch BUG_ON in list_block_add.

Reproduced by stressing concurrent quota add/del operations across mounts. Crashdump analysis confirms dirty_list_block COW'd a freed block (fr_old=9842, new blkno=9852) but by the time list_block_add ran, freed.ref.blkno was 0 with first_nr=0 and total_nr=0: the freed list head had been zeroed by a concurrent alloc_init.

Fix by adding scoutfs_hold_trans/scoutfs_release_trans around the item modification in scoutfs_quota_mod_rule, preventing transaction commit from racing with the allocator use.

@aversecat
Copy link
Copy Markdown
Contributor Author

This hit our srch and unmount testing issues.

@aversecat
Copy link
Copy Markdown
Contributor Author

retest

1 similar comment
@aversecat
Copy link
Copy Markdown
Contributor Author

retest

Comment thread kmod/src/quota.c
scoutfs_quota_mod_rule calls scoutfs_item_create/delete which use
the transaction allocator but it never held it. Without the hold,
a concurrent transaction commit can call scoutfs_alloc_init to
reinitialize the allocator while dirty_alloc_blocks is in the middle
of setting up the freed list block. This overwrites alloc->freed with
the server's fresh (empty) state, causing a blkno mismatch BUG_ON
in list_block_add.

Reproduced by stressing concurrent quota add/del operations across
mounts. Crashdump analysis confirms dirty_list_block COW'd a freed
block (fr_old=9842, new blkno=9852) but by the time list_block_add
ran, freed.ref.blkno was 0 with first_nr=0 and total_nr=0: the freed
list head had been zeroed by a concurrent alloc_init.

Fix by adding scoutfs_hold_trans/scoutfs_release_trans around the
item modification in scoutfs_quota_mod_rule, preventing transaction
commit from racing with the allocator use.

Rename the 'unlock' label to 'release' since 'out' now directly
does the unlock. The unlock safely handles a NULL lock.

Signed-off-by: Auke Kok <auke.kok@versity.com>
@aversecat aversecat force-pushed the auke/quota_mod_trans_hold branch from 72c4f83 to 9cf385d Compare April 14, 2026 17:25
@aversecat aversecat added the Bugfix Fixes a known bug label Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bugfix Fixes a known bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants