In ext2fs_extent_set_bmap() and ext2fs_punch_extent(), fix the parents when altering either end of an extent so that the parent nodes reflect the added mapping. There's a slight complication to using fix_parents: if there are two mappings to an lblk in the tree, the value of handle->path->curr can point to either extent afterwards), which is documented in a comment. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- lib/ext2fs/extent.c | 30 ++++++++++++++++++++++++------ lib/ext2fs/punch.c | 14 ++++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c index f27344e..80ce88f 100644 --- a/lib/ext2fs/extent.c +++ b/lib/ext2fs/extent.c @@ -720,7 +720,14 @@ errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, * and so on. * * Safe to call for any position in node; if not at the first entry, - * will simply return. + * it will simply return. + * + * Note a subtlety of this function -- if there happen to be two extents + * mapping the same lblk and someone calls fix_parents on the second of the two + * extents, the position of the extent handle after the call will be the second + * extent if nothing happened, or the first extent if something did. A caller + * in this situation must use ext2fs_extent_goto() after calling this function. + * Or simply don't map the same lblk with two extents, ever. */ errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle) { @@ -1379,17 +1386,25 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, &next_extent); if (retval) goto done; - retval = ext2fs_extent_fix_parents(handle); - if (retval) - goto done; } else retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &newextent); if (retval) goto done; - /* Now pointing at inserted extent; move back to prev */ + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + /* + * Now pointing at inserted extent; move back to prev. + * + * We cannot use EXT2_EXTENT_PREV to go back; note the + * subtlety in the comment for fix_parents(). + */ + retval = ext2fs_extent_goto(handle, logical); + if (retval) + goto done; retval = ext2fs_extent_get(handle, - EXT2_EXTENT_PREV_LEAF, + EXT2_EXTENT_CURRENT, &extent); if (retval) goto done; @@ -1422,6 +1437,9 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, 0, &newextent); if (retval) goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &extent); diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c index a3d020e..2a2cf10 100644 --- a/lib/ext2fs/punch.c +++ b/lib/ext2fs/punch.c @@ -343,10 +343,16 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino, EXT2_EXTENT_INSERT_AFTER, &newex); if (retval) goto errout; - /* Now pointing at inserted extent; so go back */ - retval = ext2fs_extent_get(handle, - EXT2_EXTENT_PREV_LEAF, - &newex); + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto errout; + /* + * Now pointing at inserted extent; so go back. + * + * We cannot use EXT2_EXTENT_PREV to go back; note the + * subtlety in the comment for fix_parents(). + */ + retval = ext2fs_extent_goto(handle, extent.e_lblk); if (retval) goto errout; } -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html