• Anton Altaparmakov's avatar
    Fix nasty 32-bit overflow bug in buffer i/o code. · f2d5a944
    Anton Altaparmakov authored
    On 32-bit architectures, the legacy buffer_head functions are not always
    handling the sector number with the proper 64-bit types, and will thus
    fail on 4TB+ disks.
    
    Any code that uses __getblk() (and thus bread(), breadahead(),
    sb_bread(), sb_breadahead(), sb_getblk()), and calls it using a 64-bit
    block on a 32-bit arch (where "long" is 32-bit) causes an inifinite loop
    in __getblk_slow() with an infinite stream of errors logged to dmesg
    like this:
    
      __find_get_block_slow() failed. block=6740375944, b_blocknr=2445408648
      b_state=0x00000020, b_size=512
      device sda1 blocksize: 512
    
    Note how in hex block is 0x191C1F988 and b_blocknr is 0x91C1F988 i.e. the
    top 32-bits are missing (in this case the 0x1 at the top).
    
    This is because grow_dev_page() is broken and has a 32-bit overflow due
    to shifting the page index value (a pgoff_t - which is just 32 bits on
    32-bit architectures) left-shifted as the block number.  But the top
    bits to get lost as the pgoff_t is not type cast to sector_t / 64-bit
    before the shift.
    
    This patch fixes this issue by type casting "index" to sector_t before
    doing the left shift.
    
    Note this is not a theoretical bug but has been seen in the field on a
    4TiB hard drive with logical sector size 512 bytes.
    
    This patch has been verified to fix the infinite loop problem on 3.17-rc5
    kernel using a 4TB disk image mounted using "-o loop".  Without this patch
    doing a "find /nt" where /nt is an NTFS volume causes the inifinite loop
    100% reproducibly whilst with the patch it works fine as expected.
    Signed-off-by: default avatarAnton Altaparmakov <aia21@cantab.net>
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    f2d5a944
buffer.c 88.7 KB