<div>Доброго времени суток!</div><div> </div><div>В предыдущих патчах на v6.1 и v6.12 ошибка, прошу прощения. Их не надо проверять. В скором времени вышлю исправленные версии .</div><div> </div><div>С уважением,</div><div>Семёнов М.С.</div><div>----------------</div><div>Кому: lvc-project@linuxtesting.org (lvc-project@linuxtesting.org), m.semenov@tssltd.ru (m.semenov@tssltd.ru);</div><div>Тема: [PATCH 6.1] gfs2: Improve resource group validation and error handling;</div><div>25.08.2026, 16:06, "Makar Semyonov" <m.semenov@tssltd.ru>:</div><blockquote><p>Validate the resource group boundaries, check against the device size, simplify<br />the initialization logic, and check for resource group overlaps.<br /><br />Reported-by: <a href="mailto:syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com" rel="noopener noreferrer">syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com</a><br />Closes: <a href="https://syzkaller.appspot.com/bug?extid=9d20c3ad7d29227de28d" rel="noopener noreferrer">https://syzkaller.appspot.com/bug?extid=9d20c3ad7d29227de28d</a><br />Tested-by: <a href="mailto:syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com" rel="noopener noreferrer">syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com</a><br />Signed-off-by: Andreas Gruenbacher <<a href="mailto:agruenba@redhat.com" rel="noopener noreferrer">agruenba@redhat.com</a>><br />Fixes: feaa7bba026c ("[GFS2] Fix unlinked file handling")<br />Signed-off-by: Makar Semyonov <<a href="mailto:m.semenov@tssltd.ru" rel="noopener noreferrer">m.semenov@tssltd.ru</a>><br />---<br /> fs/gfs2/rgrp.c | 128 ++++++++++++++++++++++++++-----------------------<br /> 1 file changed, 69 insertions(+), 59 deletions(-)<br /><br />diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c<br />index f602fb844951..66f34e08a346 100644<br />--- a/fs/gfs2/rgrp.c<br />+++ b/fs/gfs2/rgrp.c<br />@@ -745,6 +745,7 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)<br /> <br /> /**<br />  * compute_bitstructs - Compute the bitmap sizes<br />+ * @sb: The superblock<br />  * @rgd: The resource group descriptor<br />  *<br />  * Calculates bitmap descriptors, one for each block that contains bitmap data<br />@@ -752,84 +753,77 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)<br />  * Returns: errno<br />  */<br /> <br />-static int compute_bitstructs(struct gfs2_rgrpd *rgd)<br />+static int compute_bitstructs(struct super_block *sb, struct gfs2_rgrpd *rgd)<br /> {<!-- --><br />         struct gfs2_sbd *sdp = rgd->rd_sbd;<br />         struct gfs2_bitmap *bi;<br />- u32 length = rgd->rd_length; /* # blocks in hdr & bitmap */<br />+ u32 expected_length;<br />         u32 bytes_left, bytes;<br />+ u64 data_end;<br />         int x;<br /> <br />- if (!length)<br />- return -EINVAL;<br />+ /*<br />+ * The first resource group block has a gfs2_rgrp header; the remaining<br />+ * blocks have a gfs2_meta_header header. The rest of each block is<br />+ * filled with bitmap data.<br />+ */<br />+<br />+ if (rgd->rd_addr <= (GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift)) {<!-- --><br />+ gfs2_consist_rgrpd(rgd);<br />+ return -EIO;<br />+ }<br />+ if (check_add_overflow(rgd->rd_data0, rgd->rd_data, &data_end) ||<br />+ rgd->rd_data == 0 || data_end > sb_bdev_nr_blocks(sb)) {<!-- --><br />+ gfs2_consist_rgrpd(rgd);<br />+ return -EIO;<br />+ }<br />+ if (rgd->rd_bitbytes != DIV_ROUND_UP(rgd->rd_data, GFS2_NBBY)) {<!-- --><br />+ gfs2_consist_rgrpd(rgd);<br />+ return -EIO;<br />+ }<br />+ expected_length = DIV_ROUND_UP(rgd->rd_bitbytes +<br />+ sizeof(struct gfs2_rgrp) - sizeof(struct gfs2_meta_header),<br />+ sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header));<br />+ if (rgd->rd_length != expected_length) {<!-- --><br />+ gfs2_consist_rgrpd(rgd);<br />+ return -EIO;<br />+ }<br />+ if (rgd->rd_data0 < rgd->rd_addr + rgd->rd_length) {<!-- --><br />+ gfs2_consist_rgrpd(rgd);<br />+ return -EIO;<br />+ }<br />+<br />+ rgd->rd_bits = kcalloc(rgd->rd_length, sizeof(struct gfs2_bitmap), GFP_NOFS);<br /> <br />- rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_NOFS);<br />         if (!rgd->rd_bits)<br />                 return -ENOMEM;<br /> <br />         bytes_left = rgd->rd_bitbytes;<br /> <br />- for (x = 0; x < length; x++) {<!-- --><br />+ for (x = 0; x < rgd->rd_length; x++) {<!-- --><br />                 bi = rgd->rd_bits + x;<br /> <br />                 bi->bi_flags = 0;<br />- /* small rgrp; bitmap stored completely in header block */<br />- if (length == 1) {<!-- --><br />- bytes = bytes_left;<br />- bi->bi_offset = sizeof(struct gfs2_rgrp);<br />+ if (x == 0) {<!-- --><br />+ /* header block */<br />                         bi->bi_start = 0;<br />- bi->bi_bytes = bytes;<br />- bi->bi_blocks = bytes * GFS2_NBBY;<br />- /* header block */<br />- } else if (x == 0) {<!-- --><br />- bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp);<br />                         bi->bi_offset = sizeof(struct gfs2_rgrp);<br />- bi->bi_start = 0;<br />- bi->bi_bytes = bytes;<br />- bi->bi_blocks = bytes * GFS2_NBBY;<br />- /* last block */<br />- } else if (x + 1 == length) {<!-- --><br />- bytes = bytes_left;<br />- bi->bi_offset = sizeof(struct gfs2_meta_header);<br />- bi->bi_start = rgd->rd_bitbytes - bytes_left;<br />- bi->bi_bytes = bytes;<br />- bi->bi_blocks = bytes * GFS2_NBBY;<br />- /* other blocks */<br />                 } else {<!-- --><br />- bytes = sdp->sd_sb.sb_bsize -<br />- sizeof(struct gfs2_meta_header);<br />+ /* bitmap-only block */<br />+ struct gfs2_bitmap *prev = bi - 1;<br />+<br />+ bi->bi_start = prev->bi_start + prev->bi_bytes;<br />                         bi->bi_offset = sizeof(struct gfs2_meta_header);<br />- bi->bi_start = rgd->rd_bitbytes - bytes_left;<br />- bi->bi_bytes = bytes;<br />- bi->bi_blocks = bytes * GFS2_NBBY;<br />                 }<br />-<br />+ bytes = sdp->sd_sb.sb_bsize - bi->bi_offset;<br />+ if (bytes > bytes_left)<br />+ bytes = bytes_left;<br />+ bi->bi_bytes = bytes;<br />+ bi->bi_blocks = bytes * GFS2_NBBY;<br />                 bytes_left -= bytes;<br />         }<br />-<br />- if (bytes_left) {<!-- --><br />- gfs2_consist_rgrpd(rgd);<br />- return -EIO;<br />- }<br />- bi = rgd->rd_bits + (length - 1);<br />- if ((bi->bi_start + bi->bi_bytes) * GFS2_NBBY != rgd->rd_data) {<!-- --><br />- gfs2_lm(sdp,<br />- "ri_addr = %llu\n"<br />- "ri_length = %u\n"<br />- "ri_data0 = %llu\n"<br />- "ri_data = %u\n"<br />- "ri_bitbytes = %u\n"<br />- "start=%u len=%u offset=%u\n",<br />- (unsigned long long)rgd->rd_addr,<br />- rgd->rd_length,<br />- (unsigned long long)rgd->rd_data0,<br />- rgd->rd_data,<br />- rgd->rd_bitbytes,<br />- bi->bi_start, bi->bi_bytes, bi->bi_offset);<br />- gfs2_consist_rgrpd(rgd);<br />- return -EIO;<br />- }<br />-<br />         return 0;<br /> }<br /> <br />@@ -864,6 +858,7 @@ static int rgd_insert(struct gfs2_rgrpd *rgd)<br /> {<!-- --><br />         struct gfs2_sbd *sdp = rgd->rd_sbd;<br />         struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;<br />+ struct rb_node *prevn;<br /> <br />         /* Figure out where to put new node */<br />         while (*newn) {<!-- --><br />@@ -882,6 +877,19 @@ static int rgd_insert(struct gfs2_rgrpd *rgd)<br />         rb_link_node(&rgd->rd_node, parent, newn);<br />         rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);<br />         sdp->sd_rgrps++;<br />+<br />+ prevn = rb_prev(&rgd->rd_node);<br />+ if (prevn) {<!-- --><br />+ struct gfs2_rgrpd *prev =<br />+ rb_entry(prevn, struct gfs2_rgrpd, rd_node);<br />+<br />+ if (prev->rd_data0 + prev->rd_data > rgd->rd_addr) {<!-- --><br />+ fs_err(sdp, "overlapping resource groups.\n");<br />+ rb_erase(&rgd->rd_node, &sdp->sd_rindex_tree);<br />+ return -ENOENT;<br />+ }<br />+ }<br />+<br />         return 0;<br /> }<br /> <br />@@ -928,7 +936,7 @@ static int read_rindex_entry(struct gfs2_inode *ip)<br />         if (error)<br />                 goto fail;<br /> <br />- error = compute_bitstructs(rgd);<br />+ error = compute_bitstructs(sdp->sd_vfs, rgd);<br />         if (error)<br />                 goto fail_glock;<br /> <br />@@ -944,7 +952,9 @@ static int read_rindex_entry(struct gfs2_inode *ip)<br />                 return 0;<br />         }<br /> <br />- error = 0; /* someone else read in the rgrp; free it and ignore it */<br />+ /* If someone else read in the rgrp, free it and ignore it. */<br />+ if (error == -EEXIST)<br />+ error = 0;<br /> fail_glock:<br />         gfs2_glock_put(rgd->rd_gl);<br /> <br />@@ -2306,7 +2316,7 @@ void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd,<br />                        (unsigned long long)rgd->rd_addr, rgd->rd_flags,<br />                        rgd->rd_free, rgd->rd_free_clone, rgd->rd_dinodes,<br />                        rgd->rd_requested, rgd->rd_reserved, rgd->rd_extfail_pt);<br />- if (rgd->rd_sbd->sd_args.ar_rgrplvb) {<!-- --><br />+ if (rgd->rd_sbd->sd_args.ar_rgrplvb && rgd->rd_rgl) {<!-- --><br />                 struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl;<br /> <br />                 gfs2_print_dbg(seq, "%s L: f:%02x b:%u i:%u\n", fs_id_buf,</p>--<br />2.43.0</blockquote>