• Qu Wenruo's avatar
    btrfs: prevent extent_clear_unlock_delalloc() to unlock page not locked by __process_pages_contig() · 4750af3b
    Qu Wenruo authored
    In cow_file_range(), after we have succeeded creating an inline extent,
    we unlock the page with extent_clear_unlock_delalloc() by passing
    locked_page == NULL.
    
    For sectorsize == PAGE_SIZE case, this is just making the page lock and
    unlock harder to grab.
    
    But for incoming subpage case, it can be a big problem.
    
    For incoming subpage case, page locking have two entry points:
    
    - __process_pages_contig()
      In that case, we know exactly the range we want to lock (which only
      requires sector alignment).
      To handle the subpage requirement, we introduce btrfs_subpage::writers
      to page::private, and will update it in __process_pages_contig().
    
    - Other directly lock/unlock_page() call sites
      Those won't touch btrfs_subpage::writers at all.
    
    This means, page locked by __process_pages_contig() can only be unlocked
    by __process_pages_contig().
    Thankfully we already have the existing infrastructure in the form of
    @locked_page in various call sites.
    
    Unfortunately, extent_clear_unlock_delalloc() in cow_file_range() after
    creating an inline extent is the exception.
    It intentionally call extent_clear_unlock_delalloc() with locked_page ==
    NULL, to also unlock current page (and clear its dirty/writeback bits).
    
    To co-operate with incoming subpage modifications, and make the page
    lock/unlock pair easier to understand, this patch will still call
    extent_clear_unlock_delalloc() with locked_page, and only unlock the
    page in __extent_writepage().
    
    Tested-by: Ritesh Harjani <riteshh@linux.ibm.com> # [ppc64]
    Tested-by: Anand Jain <anand.jain@oracle.com> # [aarch64]
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    4750af3b
inode.c 299 KB