• Eryu Guan's avatar
    ext4: be more strict when migrating to non-extent based file · 5d32c2e0
    Eryu Guan authored
    commit d6f123a9 upstream.
    
    Currently the check in ext4_ind_migrate() is not enough before doing the
    real conversion:
    
    a) delayed allocated extents could bypass the check on eh->eh_entries
       and eh->eh_depth
    
    This can be demonstrated by this script
    
      xfs_io -fc "pwrite 0 4k" -c "pwrite 8k 4k" /mnt/ext4/testfile
      chattr -e /mnt/ext4/testfile
    
    where testfile has two extents but still be converted to non-extent
    based file format.
    
    b) only extent length is checked but not the offset, which would result
       in data lose (delalloc) or fs corruption (nodelalloc), because
       non-extent based file only supports at most (12 + 2^10 + 2^20 + 2^30)
       blocks
    
    This can be demostrated by
    
      xfs_io -fc "pwrite 5T 4k" /mnt/ext4/testfile
      chattr -e /mnt/ext4/testfile
      sync
    
    If delalloc is enabled, dmesg prints
      EXT4-fs warning (device dm-4): ext4_block_to_path:105: block 1342177280 > max in inode 53
      EXT4-fs (dm-4): Delayed block allocation failed for inode 53 at logical offset 1342177280 with max blocks 1 with error 5
      EXT4-fs (dm-4): This should not happen!! Data will be lost
    
    If delalloc is disabled, e2fsck -nf shows corruption
      Inode 53, i_size is 5497558142976, should be 4096.  Fix? no
    
    Fix the two issues by
    
    a) forcing all delayed allocation blocks to be allocated before checking
       eh->eh_depth and eh->eh_entries
    b) limiting the last logical block of the extent is within direct map
    Signed-off-by: default avatarEryu Guan <guaneryu@gmail.com>
    Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
    Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
    5d32c2e0
migrate.c 16.8 KB