Skip to content
  • Toshiyuki Okajima's avatar
    ext4: improve llseek error handling for overly large seek offsets · e0d10bfa
    Toshiyuki Okajima authored
    
    
    The llseek system call should return EINVAL if passed a seek offset
    which results in a write error.  What this maximum offset should be
    depends on whether or not the huge_file file system feature is set,
    and whether or not the file is extent based or not.
    
    
    If the file has no "EXT4_EXTENTS_FL" flag, the maximum size which can be 
    written (write systemcall) is different from the maximum size which can be 
    sought (lseek systemcall).
    
    For example, the following 2 cases demonstrates the differences
    between the maximum size which can be written, versus the seek offset
    allowed by the llseek system call:
    
    #1: mkfs.ext3 <dev>; mount -t ext4 <dev>
    #2: mkfs.ext3 <dev>; tune2fs -Oextent,huge_file <dev>; mount -t ext4 <dev>
    
    Table. the max file size which we can write or seek
           at each filesystem feature tuning and file flag setting
    +============+===============================+===============================+
    | \ File flag|                               |                               |
    |      \     |     !EXT4_EXTENTS_FL          |        EXT4_EXTETNS_FL        |
    |case       \|                               |                               |
    +------------+-------------------------------+-------------------------------+
    | #1         |   write:      2194719883264   | write:       --------------   |
    |            |   seek:       2199023251456   | seek:        --------------   |
    +------------+-------------------------------+-------------------------------+
    | #2         |   write:      4402345721856   | write:       17592186044415   |
    |            |   seek:      17592186044415   | seek:        17592186044415   |
    +------------+-------------------------------+-------------------------------+
    
    The differences exist because ext4 has 2 maxbytes which are sb->s_maxbytes
    (= extent-mapped maxbytes) and EXT4_SB(sb)->s_bitmap_maxbytes (= block-mapped 
    maxbytes).  Although generic_file_llseek uses only extent-mapped maxbytes.
    (llseek of ext4_file_operations is generic_file_llseek which uses
    sb->s_maxbytes.)
    
    Therefore we create ext4 llseek function which uses 2 maxbytes.
    
    The new own function originates from generic_file_llseek().
    If the file flag, "EXT4_EXTENTS_FL" is not set, the function alters 
    inode->i_sb->s_maxbytes into EXT4_SB(inode->i_sb)->s_bitmap_maxbytes.
    
    Signed-off-by: default avatarToshiyuki Okajima <toshi.okajima@jp.fujitsu.com>
    Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
    Cc: Andreas Dilger <adilger.kernel@dilger.ca>
    e0d10bfa