On Thu, Mar 12, 2020 at 10:57:28AM +0200, Tommi Rantala wrote: > Commit 263dde869bd09 ("xfs: cleanup xfs_dir2_block_getdents") introduced > a getdents regression, when it converted the pointer arithmetics to > offset calculations: offset is updated in the loop already for the next > iteration, but the updated offset value is used incorrectly in two > places, where we should have used the not-yet-updated value. > > This caused for example "git clean -ffdx" failures to cleanup certain > directory structures when running in a container. > > Fix the regression by making sure we use proper offset in the loop body. > Thanks to Christoph Hellwig for suggestion how to best fix the code. > > Cc: Christoph Hellwig <hch@xxxxxx> > Fixes: 263dde869bd09 ("xfs: cleanup xfs_dir2_block_getdents") > Signed-off-by: Tommi Rantala <tommi.t.rantala@xxxxxxxxx> Looks ok, sorry I didn't catch this either... Reviewed-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> How might we package this up as a fstest so we can actually do regression testing? --D > --- > fs/xfs/xfs_dir2_readdir.c | 12 +++++++----- > 1 file changed, 7 insertions(+), 5 deletions(-) > > diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c > index 0d3b640cf1cc..871ec22c9aee 100644 > --- a/fs/xfs/xfs_dir2_readdir.c > +++ b/fs/xfs/xfs_dir2_readdir.c > @@ -147,7 +147,7 @@ xfs_dir2_block_getdents( > xfs_off_t cook; > struct xfs_da_geometry *geo = args->geo; > int lock_mode; > - unsigned int offset; > + unsigned int offset, next_offset; > unsigned int end; > > /* > @@ -173,9 +173,10 @@ xfs_dir2_block_getdents( > * Loop over the data portion of the block. > * Each object is a real entry (dep) or an unused one (dup). > */ > - offset = geo->data_entry_offset; > end = xfs_dir3_data_end_offset(geo, bp->b_addr); > - while (offset < end) { > + for (offset = geo->data_entry_offset; > + offset < end; > + offset = next_offset) { > struct xfs_dir2_data_unused *dup = bp->b_addr + offset; > struct xfs_dir2_data_entry *dep = bp->b_addr + offset; > uint8_t filetype; > @@ -184,14 +185,15 @@ xfs_dir2_block_getdents( > * Unused, skip it. > */ > if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { > - offset += be16_to_cpu(dup->length); > + next_offset = offset + be16_to_cpu(dup->length); > continue; > } > > /* > * Bump pointer for the next iteration. > */ > - offset += xfs_dir2_data_entsize(dp->i_mount, dep->namelen); > + next_offset = offset + > + xfs_dir2_data_entsize(dp->i_mount, dep->namelen); > > /* > * The entry is before the desired starting point, skip it. > -- > 2.21.1 >