• Long Li's avatar
    xfs: fix ag count overflow during growfs · c3b880ac
    Long Li authored
    I found a corruption during growfs:
    
     XFS (loop0): Internal error agbno >= mp->m_sb.sb_agblocks at line 3661 of
       file fs/xfs/libxfs/xfs_alloc.c.  Caller __xfs_free_extent+0x28e/0x3c0
     CPU: 0 PID: 573 Comm: xfs_growfs Not tainted 6.3.0-rc7-next-20230420-00001-gda8c95746257
     Call Trace:
      <TASK>
      dump_stack_lvl+0x50/0x70
      xfs_corruption_error+0x134/0x150
      __xfs_free_extent+0x2c1/0x3c0
      xfs_ag_extend_space+0x291/0x3e0
      xfs_growfs_data+0xd72/0xe90
      xfs_file_ioctl+0x5f9/0x14a0
      __x64_sys_ioctl+0x13e/0x1c0
      do_syscall_64+0x39/0x80
      entry_SYSCALL_64_after_hwframe+0x63/0xcd
     XFS (loop0): Corruption detected. Unmount and run xfs_repair
     XFS (loop0): Internal error xfs_trans_cancel at line 1097 of file
       fs/xfs/xfs_trans.c.  Caller xfs_growfs_data+0x691/0xe90
     CPU: 0 PID: 573 Comm: xfs_growfs Not tainted 6.3.0-rc7-next-20230420-00001-gda8c95746257
     Call Trace:
      <TASK>
      dump_stack_lvl+0x50/0x70
      xfs_error_report+0x93/0xc0
      xfs_trans_cancel+0x2c0/0x350
      xfs_growfs_data+0x691/0xe90
      xfs_file_ioctl+0x5f9/0x14a0
      __x64_sys_ioctl+0x13e/0x1c0
      do_syscall_64+0x39/0x80
      entry_SYSCALL_64_after_hwframe+0x63/0xcd
     RIP: 0033:0x7f2d86706577
    
    The bug can be reproduced with the following sequence:
    
     # truncate -s  1073741824 xfs_test.img
     # mkfs.xfs -f -b size=1024 -d agcount=4 xfs_test.img
     # truncate -s 2305843009213693952  xfs_test.img
     # mount -o loop xfs_test.img /mnt/test
     # xfs_growfs -D  1125899907891200  /mnt/test
    
    The root cause is that during growfs, user space passed in a large value
    of newblcoks to xfs_growfs_data_private(), due to current sb_agblocks is
    too small, new AG count will exceed UINT_MAX. Because of AG number type
    is unsigned int and it would overflow, that caused nagcount much smaller
    than the actual value. During AG extent space, delta blocks in
    xfs_resizefs_init_new_ags() will much larger than the actual value due to
    incorrect nagcount, even exceed UINT_MAX. This will cause corruption and
    be detected in __xfs_free_extent. Fix it by growing the filesystem to up
    to the maximally allowed AGs and not return EINVAL when new AG count
    overflow.
    Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
    Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
    Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
    c3b880ac
xfs_fs.h 31.8 KB