• Darrick J. Wong's avatar
    xfs: fix interval filtering in multi-step fsmap queries · 63ef7a35
    Darrick J. Wong authored
    I noticed a bug in ranged GETFSMAP queries:
    
    # xfs_io -c 'fsmap -vvvv' /opt
     EXT: DEV  BLOCK-RANGE           OWNER              FILE-OFFSET      AG AG-OFFSET           TOTAL
       0: 8:80 [0..7]:               static fs metadata                  0  (0..7)                  8
    <snip>
       9: 8:80 [192..223]:           137                0..31            0  (192..223)             32
    # xfs_io -c 'fsmap -vvvv -d 208 208' /opt
    #
    
    That's not right -- we asked what block maps block 208, and we should've
    received a mapping for inode 137 offset 16.  Instead, we get nothing.
    
    The root cause of this problem is a mis-interaction between the fsmap
    code and how btree ranged queries work.  xfs_btree_query_range returns
    any btree record that overlaps with the query interval, even if the
    record starts before or ends after the interval.  Similarly, GETFSMAP is
    supposed to return a recordset containing all records that overlap the
    range queried.
    
    However, it's possible that the recordset is larger than the buffer that
    the caller provided to convey mappings to userspace.  In /that/ case,
    userspace is supposed to copy the last record returned to fmh_keys[0]
    and call GETFSMAP again.  In this case, we do not want to return
    mappings that we have already supplied to the caller.  The call to
    xfs_btree_query_range is the same, but now we ignore any records that
    start before fmh_keys[0].
    
    Unfortunately, we didn't implement the filtering predicate correctly.
    The predicate should only be called when we're calling back for more
    records.  Accomplish this by setting info->low.rm_blockcount to a
    nonzero value and ensuring that it is cleared as necessary.  As a
    result, we no longer want to adjust dkeys[0] in the main setup function
    because that's confusing.
    
    This patch doesn't touch the logdev/rtbitmap backends because they have
    bigger problems that will be addressed by subsequent patches.
    
    Found via xfs/556 with parent pointers enabled.
    
    Fixes: e89c0413 ("xfs: implement the GETFSMAP ioctl")
    Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
    Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
    63ef7a35
xfs_fsmap.c 26.9 KB