• Brian Foster's avatar
    xfs: prevent multi-fsb dir readahead from reading random blocks · 022e9b0e
    Brian Foster authored
    [ Upstream commit cb52ee33 ]
    
    Directory block readahead uses a complex iteration mechanism to map
    between high-level directory blocks and underlying physical extents.
    This mechanism attempts to traverse the higher-level dir blocks in a
    manner that handles multi-fsb directory blocks and simultaneously
    maintains a reference to the corresponding physical blocks.
    
    This logic doesn't handle certain (discontiguous) physical extent
    layouts correctly with multi-fsb directory blocks. For example,
    consider the case of a 4k FSB filesystem with a 2 FSB (8k) directory
    block size and a directory with the following extent layout:
    
     EXT: FILE-OFFSET      BLOCK-RANGE      AG AG-OFFSET        TOTAL
       0: [0..7]:          88..95            0 (88..95)             8
       1: [8..15]:         80..87            0 (80..87)             8
       2: [16..39]:        168..191          0 (168..191)          24
       3: [40..63]:        5242952..5242975  1 (72..95)            24
    
    Directory block 0 spans physical extents 0 and 1, dirblk 1 lies
    entirely within extent 2 and dirblk 2 spans extents 2 and 3. Because
    extent 2 is larger than the directory block size, the readahead code
    erroneously assumes the block is contiguous and issues a readahead
    based on the physical mapping of the first fsb of the dirblk. This
    results in read verifier failure and a spurious corruption or crc
    failure, depending on the filesystem format.
    
    Further, the subsequent readahead code responsible for walking
    through the physical table doesn't correctly advance the physical
    block reference for dirblk 2. Instead of advancing two physical
    filesystem blocks, the first iteration of the loop advances 1 block
    (correctly), but the subsequent iteration advances 2 more physical
    blocks because the next physical extent (extent 3, above) happens to
    cover more than dirblk 2. At this point, the higher-level directory
    block walking is completely off the rails of the actual physical
    layout of the directory for the respective mapping table.
    
    Update the contiguous dirblock logic to consider the current offset
    in the physical extent to avoid issuing directory readahead to
    unrelated blocks. Also, update the mapping table advancing code to
    consider the current offset within the current dirblock to avoid
    advancing the mapping reference too far beyond the dirblock.
    Signed-off-by: default avatarBrian Foster <bfoster@redhat.com>
    Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
    022e9b0e
xfs_dir2_readdir.c 17.7 KB