xfs_repair fixes for fragmented multiblock v2 dirs
cover xfs_repair fixes for fragmented multiblock v2 dirs
3 fixes for xfs_repair on fragmented multiblock v2 dirs.
xfs_repair: Fix fragmented multiblock dir2 handling in blkmap_getn()xfs_repair: Document & robustify blkmap_next_off()xfs_repair: handle fragmented multiblock dir2 in process_leaf_node_dir2()
xfs_check seems to handle things just fine, interstingly enough.
-Eric
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/3 xfs_repair: Fix fragmented multiblock dir2 handling in blkmap_getn()
blkmap_getn() contains a loop which populates an array of extents with mapping information for a dir2 "block," which may consist of multiple filesystem blocks.
As written, the loop re-allocates the array for each new extent, leaking the previously allocated memory and worse, losing the previously filled-in extent information.
Fix this by only allocating the array once, for the maximum possible number of extents - the number of fs blocks in the dir block.
---
repair/bmap.c +2 -1
@@ -168,7 +168,8 @@ blkmap_getn(/* * rare case - multiple extents for a single dir block */ - bmp =malloc (nb *sizeof (bmap_ext_t)); +if (!bmp) + bmp =malloc (nb *sizeof (bmap_ext_t));if (!bmp)do_error (_ ("blkmap_getn malloc failed (%" PRIu64" bytes)\n" ), nb *sizeof (bmap_ext_t));
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/3] xfs_repair: Fix fragmented multiblock dir2 handling in blkmap_getn()
Hey Eric,
Quoted 20 lines · Eric Sandeen
blkmap_getn()contains a loop which populates an array of extents with mapping information for a dir2 "block," which may consist of multiple filesystem blocks.As written, the loop re-allocates the array for each new extent, leaking the previously allocated memory and worse, losing the previously filled-in extent information.
Fix this by only allocating the array once, for the maximum possible number of extents - the number of fs blocks in the dir block.
Signed-off-by Eric Sandeen <[email protected]>---
repair/bmap.c +0
-0
repair/bmap.c blkmap_getn( · line 172
Quoted 6 lines
repair/bmap.c +2
-1@@ -168,7 +168,8 @@ blkmap_getn(/* * rare case - multiple extents for a single dir block */ - bmp =malloc (nb *sizeof (bmap_ext_t)); +if (!bmp) + bmp =malloc (nb *sizeof (bmap_ext_t));
Cool. That's an area where we don't have much test coverage. I don't see a single '-n size' in xfstests.
This looks good to me. FWICS all the callers free it later.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 9 lines · Eric Sandeen
3 fixes for
xfs_repairon fragmented multiblock v2 dirs.
xfs_repair: Fix fragmented multiblock dir2 handling inblkmap_getn()xfs_repair: Document & robustifyblkmap_next_off()xfs_repair: handle fragmented multiblock dir2 inprocess_leaf_node_dir2()
xfs_checkseems to handle things just fine, interstingly enough.-Eric
Grr.
Well, I did send the other two.
but it seems to be eaten/stuck/constipated. Again.
Grr.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH RESEND 2/3 xfs_repair fixes for fragmented multiblock v2 dirs
In reply to Eric Sandeenblkmap_next_off() was cryptic (to me), so document what it does. Also catch cases when the passed in extent index 't' is beyond the number of extents in the blkmap, so that:
ext = blkmap->exts + *t;
doesn't walk off the end of the array into garbage.
---
Resending, last one never made it through the mailing list gauntlet...
repair/bmap.c +22 -3
@@ -206,8 +206,25 @@ blkmap_last_off(return ext->startoff + ext->blockcount; } -/* -* Return the next offset in a block map. +/** +* blkmap_next_off - Return next logical block offset in a block map. +* @blkmap: blockmap to use +* @o: current file logical block number +* @t: current extent index into blockmap (in/out) +* +* Given a logical block offset in a file, return the next mapped logical offset +* The map index "t" tracks the current extent number in the block map, and +* is updated automatically if the returned offset resides within the next +* mapped extent. +* +* If the blockmap contains no extents, or no more logical offsets are mapped, +* or the extent index exceeds the number of extents in the map, +* return NULLDFILOFF. +* +* If offset o is beyond extent index t, the first offset in the next extent +* after extent t will be returned. +* +* Intended to be called starting with offset 0, index 0, and iterated. */ xfs_dfiloff_t blkmap_next_off(
@@ -223,10 +240,12 @@ blkmap_next_off( *t =0 ;return blkmap->exts[0 ].startoff; } +if (*t >= blkmap->nexts) +return NULLDFILOFF ; ext = blkmap->exts + *t;if (o < ext->startoff + ext->blockcount -1 )return o +1 ; -if (*t >= blkmap->nexts -1 ) +if (*t == blkmap->nexts -1 )return NULLDFILOFF ; (*t)++;return ext[1 ].startoff;
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH RESEND 3/3 xfs_repair: handle fragmented multiblock dir2 in process_leaf_node_dir2()
In reply to Eric Sandeenprocess_leaf_node_dir2() had the following loop:
while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) {
...
ndbno = dbno + mp->m_dirblkfsbs - 1;
...
}which does not account for fragmented multiblock dir2.
ndbno was blindly being advanced by m_dirblkfsbs, but then blkmap_next_off() would return the logical block of the next mapped extent in blkmap, which may be within the current (fragmented) dir2 multi-block, not the next multi-block, because the extent index t hadn't been advanced.
Fix this by calling blkmap_next_off() until ndbno has advanced into the next multiblock dir2 block, thereby keeping the extent index t straight while properly advancing ndbno.
---
Resending, first one didn't make it through the mailing list gauntlet
repair/dir2.c +5 -1
@@ -2003,7 +2003,11 @@ process_leaf_node_dir2( ndbno =NULLDFILOFF ;while ((dbno =blkmap_next_off (blkmap, ndbno, &t)) < mp->m_dirleafblk) { nex =blkmap_getn (blkmap, dbno, mp->m_dirblkfsbs, &bmp, &lbmp); - ndbno = dbno + mp->m_dirblkfsbs -1 ; +/* Advance through map to last dfs block in this dir block */ + ndbno = dbno; +while (ndbno < dbno + mp->m_dirblkfsbs -1 ) { + ndbno =blkmap_next_off (blkmap, ndbno, &t); + }if (nex ==0 ) { do_warn( _("block %" PRIu64 " for directory inode %" PRIu64 " is missing\n"),
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 2/3 xfs_repair: Document & robustify blkmap_next_off()
In reply to Eric Sandeenblkmap_next_off() was cryptic (to me), so document what it does. Also catch cases when the passed in extent index 't' is beyond the number of extents in the blkmap, so that:
ext = blkmap->exts + *t;
doesn't walk off the end of the array into garbage.
---
repair/bmap.c +22 -3
@@ -206,8 +206,25 @@ blkmap_last_off(return ext->startoff + ext->blockcount; } -/* -* Return the next offset in a block map. +/** +* blkmap_next_off - Return next logical block offset in a block map. +* @blkmap: blockmap to use +* @o: current file logical block number +* @t: current extent index into blockmap (in/out) +* +* Given a logical block offset in a file, return the next mapped logical offset +* The map index "t" tracks the current extent number in the block map, and +* is updated automatically if the returned offset resides within the next +* mapped extent. +* +* If the blockmap contains no extents, or no more logical offsets are mapped, +* or the extent index exceeds the number of extents in the map, +* return NULLDFILOFF. +* +* If offset o is beyond extent index t, the first offset in the next extent +* after extent t will be returned. +* +* Intended to be called starting with offset 0, index 0, and iterated. */ xfs_dfiloff_t blkmap_next_off(
@@ -223,10 +240,12 @@ blkmap_next_off( *t =0 ;return blkmap->exts[0 ].startoff; } +if (*t >= blkmap->nexts) +return NULLDFILOFF ; ext = blkmap->exts + *t;if (o < ext->startoff + ext->blockcount -1 )return o +1 ; -if (*t >= blkmap->nexts -1 ) +if (*t == blkmap->nexts -1 )return NULLDFILOFF ; (*t)++;return ext[1 ].startoff;
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 2/3] xfs_repair: Document & robustify blkmap_next_off()
Quoted 47 lines · Eric Sandeen
blkmap_next_off()was cryptic (to me), so document what it does. Also catch cases when the passed in extent index 't' is beyond the number of extents in the blkmap, so that:ext = blkmap->exts + *t;doesn't walk off the end of the array into garbage.
Signed-off-by Eric Sandeen <[email protected]>---
repair/bmap.c +19
-2@@ -206,8 +206,25 @@ blkmap_last_off(return ext->startoff + ext->blockcount; } -/* -* Return the next offset in a block map. +/** +* blkmap_next_off - Return next logical block offset in a block map. +* @blkmap: blockmap to use +* @o: current file logical block number +* @t: current extent index into blockmap (in/out) +* +* Given a logical block offset in a file, return the next mapped logical offset +* The map index "t" tracks the current extent number in the block map, and +* is updated automatically if the returned offset resides within the next +* mapped extent. +* +* If the blockmap contains no extents, or no more logical offsets are mapped, +* or the extent index exceeds the number of extents in the map, +* return NULLDFILOFF. +* +* If offset o is beyond extent index t, the first offset in the next extent +* after extent t will be returned. +* +* Intended to be called starting with offset 0, index 0, and iterated. */ xfs_dfiloff_t blkmap_next_off(@@ -223,10 +240,12 @@ blkmap_next_off( *t =0 ;return blkmap->exts[0 ].startoff; }
repair/bmap.c blkmap_next_off( · line 251
Quoted 10 lines
repair/bmap.c +3
-1+if (*t >= blkmap->nexts) +return NULLDFILOFF ; ext = blkmap->exts + *t;if (o < ext->startoff + ext->blockcount -1 )return o +1 ; -if (*t >= blkmap->nexts -1 ) +if (*t == blkmap->nexts -1 )return NULLDFILOFF ; (*t)++;return ext[1 ].startoff;
Ok, so you have 50 extents, and when *t == 49 you don't want to go looking at ext[50].startoff. Looks good to me.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 3/3 xfs_repair: handle fragmented multiblock dir2 in process_leaf_node_dir2()
In reply to Eric Sandeenprocess_leaf_node_dir2() had the following loop:
while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) {
...
ndbno = dbno + mp->m_dirblkfsbs - 1;
...
}which does not account for fragmented multiblock dir2.
ndbno was blindly being advanced by m_dirblkfsbs, but then blkmap_next_off() would return the logical block of the next mapped extent in blkmap, which may be within the current (fragmented) dir2 multi-block, not the next multi-block, because the extent index t hadn't been advanced.
Fix this by calling blkmap_next_off() until ndbno has advanced into the next multiblock dir2 block, thereby keeping the extent index t straight while properly advancing ndbno.
---
repair/dir2.c +5 -1
@@ -2003,7 +2003,11 @@ process_leaf_node_dir2( ndbno =NULLDFILOFF ;while ((dbno =blkmap_next_off (blkmap, ndbno, &t)) < mp->m_dirleafblk) { nex =blkmap_getn (blkmap, dbno, mp->m_dirblkfsbs, &bmp, &lbmp); - ndbno = dbno + mp->m_dirblkfsbs -1 ; +/* Advance through map to last dfs block in this dir block */ + ndbno = dbno; +while (ndbno < dbno + mp->m_dirblkfsbs -1 ) { + ndbno =blkmap_next_off (blkmap, ndbno, &t); + }if (nex ==0 ) { do_warn( _("block %" PRIu64 " for directory inode %" PRIu64 " is missing\n"),
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 3/3] xfs_repair: handle fragmented multiblock dir2 in process_leaf_node_dir2()
Quoted 29 lines · Eric Sandeen
process_leaf_node_dir2()had the following loop:while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) { ... ndbno = dbno + mp->m_dirblkfsbs - 1; ... }which does not account for fragmented multiblock dir2.
ndbno was blindly being advanced by
m_dirblkfsbs, but thenblkmap_next_off()would return the logical block of the next mapped extent in blkmap, which may be within the current (fragmented) dir2 multi-block, not the next multi-block, because the extent index t hadn't been advanced.Fix this by calling
blkmap_next_off()until ndbno has advanced into the next multiblock dir2 block, thereby keeping the extent index t straight while properly advancing ndbno.Signed-off-by Eric Sandeen <[email protected]>---
repair/dir2.c +0
-0
repair/dir2.c process_leaf_node_dir2( · line 2010
Quoted 9 lines
repair/dir2.c +5
-1@@ -2003,7 +2003,11 @@ process_leaf_node_dir2( ndbno =NULLDFILOFF ;while ((dbno =blkmap_next_off (blkmap, ndbno, &t)) < mp->m_dirleafblk) { nex =blkmap_getn (blkmap, dbno, mp->m_dirblkfsbs, &bmp, &lbmp); - ndbno = dbno + mp->m_dirblkfsbs -1 ; +/* Advance through map to last dfs block in this dir block */ + ndbno = dbno; +while (ndbno < dbno + mp->m_dirblkfsbs -1 ) { + ndbno =blkmap_next_off (blkmap, ndbno, &t); + }
Yep, looks good to me. An important thing to notice is that blkmap_getn handles all extents in a dir2 multiblock...
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs