• Damien Le Moal's avatar
    zonefs: fix zonefs_iomap_begin() for reads · c1c1204c
    Damien Le Moal authored
    If a readahead is issued to a sequential zone file with an offset
    exactly equal to the current file size, the iomap type is set to
    IOMAP_UNWRITTEN, which will prevent an IO, but the iomap length is
    calculated as 0. This causes a WARN_ON() in iomap_iter():
    
    [17309.548939] WARNING: CPU: 3 PID: 2137 at fs/iomap/iter.c:34 iomap_iter+0x9cf/0xe80
    [...]
    [17309.650907] RIP: 0010:iomap_iter+0x9cf/0xe80
    [...]
    [17309.754560] Call Trace:
    [17309.757078]  <TASK>
    [17309.759240]  ? lock_is_held_type+0xd8/0x130
    [17309.763531]  iomap_readahead+0x1a8/0x870
    [17309.767550]  ? iomap_read_folio+0x4c0/0x4c0
    [17309.771817]  ? lockdep_hardirqs_on_prepare+0x400/0x400
    [17309.778848]  ? lock_release+0x370/0x750
    [17309.784462]  ? folio_add_lru+0x217/0x3f0
    [17309.790220]  ? reacquire_held_locks+0x4e0/0x4e0
    [17309.796543]  read_pages+0x17d/0xb60
    [17309.801854]  ? folio_add_lru+0x238/0x3f0
    [17309.807573]  ? readahead_expand+0x5f0/0x5f0
    [17309.813554]  ? policy_node+0xb5/0x140
    [17309.819018]  page_cache_ra_unbounded+0x27d/0x450
    [17309.825439]  filemap_get_pages+0x500/0x1450
    [17309.831444]  ? filemap_add_folio+0x140/0x140
    [17309.837519]  ? lock_is_held_type+0xd8/0x130
    [17309.843509]  filemap_read+0x28c/0x9f0
    [17309.848953]  ? zonefs_file_read_iter+0x1ea/0x4d0 [zonefs]
    [17309.856162]  ? trace_contention_end+0xd6/0x130
    [17309.862416]  ? __mutex_lock+0x221/0x1480
    [17309.868151]  ? zonefs_file_read_iter+0x166/0x4d0 [zonefs]
    [17309.875364]  ? filemap_get_pages+0x1450/0x1450
    [17309.881647]  ? __mutex_unlock_slowpath+0x15e/0x620
    [17309.888248]  ? wait_for_completion_io_timeout+0x20/0x20
    [17309.895231]  ? lock_is_held_type+0xd8/0x130
    [17309.901115]  ? lock_is_held_type+0xd8/0x130
    [17309.906934]  zonefs_file_read_iter+0x356/0x4d0 [zonefs]
    [17309.913750]  new_sync_read+0x2d8/0x520
    [17309.919035]  ? __x64_sys_lseek+0x1d0/0x1d0
    
    Furthermore, this causes iomap_readahead() to loop forever as
    iomap_readahead_iter() always returns 0, making no progress.
    
    Fix this by treating reads after the file size as access to holes,
    setting the iomap type to IOMAP_HOLE, the iomap addr to IOMAP_NULL_ADDR
    and using the length argument as is for the iomap length. To simplify
    the code with this change, zonefs_iomap_begin() is split into the read
    variant, zonefs_read_iomap_begin() and zonefs_read_iomap_ops, and the
    write variant, zonefs_write_iomap_begin() and zonefs_write_iomap_ops.
    Reported-by: default avatarJorgen Hansen <Jorgen.Hansen@wdc.com>
    Fixes: 8dcc1a9d ("fs: New zonefs file system")
    Signed-off-by: default avatarDamien Le Moal <damien.lemoal@opensource.wdc.com>
    Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
    Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
    Reviewed-by: default avatarJorgen Hansen <Jorgen.Hansen@wdc.com>
    c1c1204c
super.c 50.3 KB