* Eric Whitney <enwlinux@xxxxxxxxx>: > * Ye Bin <yebin@xxxxxxxxxxxxxxx>: > > From: Ye Bin <yebin10@xxxxxxxxxx> > > > > Syzbot report issue as follows: > > EXT4-fs error (device loop0): ext4_validate_block_bitmap:398: comm rep: bg 0: block 5: invalid block bitmap > > EXT4-fs (loop0): Delayed block allocation failed for inode 18 at logical offset 0 with max blocks 32 with error 28 > > EXT4-fs (loop0): This should not happen!! Data will be lost > > > > EXT4-fs (loop0): Total free blocks count 0 > > EXT4-fs (loop0): Free/Dirty block details > > EXT4-fs (loop0): free_blocks=0 > > EXT4-fs (loop0): dirty_blocks=32 > > EXT4-fs (loop0): Block reservation details > > EXT4-fs (loop0): i_reserved_data_blocks=2 > > EXT4-fs (loop0): Inode 18 (00000000845cd634): i_reserved_data_blocks (1) not cleared! > > > > Above issue happens as follows: > > Assume: > > sbi->s_cluster_ratio = 16 > > Step1: Insert delay block [0, 31] -> ei->i_reserved_data_blocks=2 > > Step2: > > ext4_writepages > > mpage_map_and_submit_extent -> return failed > > mpage_release_unused_pages -> to release [0, 30] > > ext4_es_remove_extent -> remove lblk=0 end=30 > > __es_remove_extent -> len1=0 len2=31-30=1 > > __es_remove_extent: > > ... > > if (len2 > 0) { > > ... > > if (len1 > 0) { > > ... > > } else { > > es->es_lblk = end + 1; > > es->es_len = len2; > > ... > > } > > if (count_reserved) > > count_rsvd(inode, lblk, orig_es.es_len - len1 - len2, &orig_es, &rc); > > goto out; -> will return but didn't calculate 'reserved' > > ... > > Step3: ext4_destroy_inode -> trigger "i_reserved_data_blocks (1) not cleared!" > > > > To solve above issue if 'len2>0' call 'get_rsvd()' before goto out. > > > > Reported-by: syzbot+05a0f0ccab4a25626e38@xxxxxxxxxxxxxxxxxxxxxxxxx > > Fixes: 8fcc3a580651 ("ext4: rework reserved cluster accounting when invalidating pages") > > Signed-off-by: Ye Bin <yebin10@xxxxxxxxxx> > > --- > > fs/ext4/extents_status.c | 3 ++- > > 1 file changed, 2 insertions(+), 1 deletion(-) > > > > diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c > > index cd0a861853e3..7ada374ff27d 100644 > > --- a/fs/ext4/extents_status.c > > +++ b/fs/ext4/extents_status.c > > @@ -1371,7 +1371,7 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, > > if (count_reserved) > > count_rsvd(inode, lblk, orig_es.es_len - len1 - len2, > > &orig_es, &rc); > > - goto out; > > + goto out_get_reserved; > > } > > > > if (len1 > 0) { > > @@ -1413,6 +1413,7 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, > > } > > } > > > > +out_get_reserved: > > if (count_reserved) > > *reserved = get_rsvd(inode, end, es, &rc); > > out: > > The length of some lines in the commit description - probably those which are > log output - is resulting in a checkpatch warning. It generally prefers lines > to be a maximum of 75 characters (and Ted usually likes them limited to 72 > characters. See my comment to patch #3. I'm not sure what Ted would want here, > though I'd probably break them at 72 characters or less. > > Otherwise, the patch looks good. Feel free to add: > Looks good. As before, feel free to add: > Reviewed-by: Eric Whitney <enwlinux@xxxxxxxxx> > > > -- > > 2.31.1 > >