• Ethan Lien's avatar
    btrfs: remove unnecessary EXTENT_UPTODATE state in buffered I/O path · 52b029f4
    Ethan Lien authored
    After we copied data to page cache in buffered I/O, we
    1. Insert a EXTENT_UPTODATE state into inode's io_tree, by
       endio_readpage_release_extent(), set_extent_delalloc() or
       set_extent_defrag().
    2. Set page uptodate before we unlock the page.
    
    But the only place we check io_tree's EXTENT_UPTODATE state is in
    btrfs_do_readpage(). We know we enter btrfs_do_readpage() only when we
    have a non-uptodate page, so it is unnecessary to set EXTENT_UPTODATE.
    
    For example, when performing a buffered random read:
    
    	fio --rw=randread --ioengine=libaio --direct=0 --numjobs=4 \
    		--filesize=32G --size=4G --bs=4k --name=job \
    		--filename=/mnt/file --name=job
    
    Then check how many extent_state in io_tree:
    
    	cat /proc/slabinfo | grep btrfs_extent_state | awk '{print $2}'
    
    w/o this patch, we got 640567 btrfs_extent_state.
    w/  this patch, we got    204 btrfs_extent_state.
    
    Maintaining such a big tree brings overhead since every I/O needs to insert
    EXTENT_LOCKED, insert EXTENT_UPTODATE, then remove EXTENT_LOCKED. And in
    every insert or remove, we need to lock io_tree, do tree search, alloc or
    dealloc extent states. By removing unnecessary EXTENT_UPTODATE, we keep
    io_tree in a minimal size and reduce overhead when performing buffered I/O.
    Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
    Reviewed-by: default avatarRobbie Ko <robbieko@synology.com>
    Signed-off-by: default avatarEthan Lien <ethanlien@synology.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    52b029f4
inode.c 327 KB