• Boris Burkov's avatar
    btrfs: fix folio refcount in btrfs_do_encoded_write() · da0386c1
    Boris Burkov authored
    The conversion to folios switched __free_page() to __folio_put() in the
    error path in btrfs_do_encoded_write().
    
    However, this gets the page refcounting wrong. If we do hit that error
    path (I reproduced by modifying btrfs_do_encoded_write to pretend to
    always fail in a way that jumps to out_folios and running the fstests
    case btrfs/281), then we always hit the following BUG freeing the folio:
    
      BUG: Bad page state in process btrfs  pfn:40ab0b
      page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x61be5 pfn:0x40ab0b
       flags: 0x5ffff0000000000(node=0|zone=2|lastcpupid=0x1ffff)
      raw: 05ffff0000000000 0000000000000000 dead000000000122 0000000000000000
      raw: 0000000000061be5 0000000000000000 00000001ffffffff 0000000000000000
      page dumped because: nonzero _refcount
      Call Trace:
      <TASK>
      dump_stack_lvl+0x3d/0xe0
      bad_page+0xea/0xf0
      free_unref_page+0x8e1/0x900
      ? __mem_cgroup_uncharge+0x69/0x90
      __folio_put+0xe6/0x190
      btrfs_do_encoded_write+0x445/0x780
      ? current_time+0x25/0xd0
      btrfs_do_write_iter+0x2cc/0x4b0
      btrfs_ioctl_encoded_write+0x2b6/0x340
    
    It turns out __free_page() decreases the page reference count while
    __folio_put() does not. Switch __folio_put() to folio_put() which
    decreases the folio reference count first.
    
    Fixes: 400b172b ("btrfs: compression: migrate compression/decompression paths to folios")
    Tested-by: default avatarEd Tomlinson <edtoml@gmail.com>
    Reviewed-by: default avatarQu Wenruo <wqu@suse.com>
    Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarBoris Burkov <boris@bur.io>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    da0386c1
inode.c 313 KB