162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#ifndef BTRFS_SUBPAGE_H 462306a36Sopenharmony_ci#define BTRFS_SUBPAGE_H 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/spinlock.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Extra info for subpapge bitmap. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * For subpage we pack all uptodate/dirty/writeback/ordered bitmaps into 1262306a36Sopenharmony_ci * one larger bitmap. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This structure records how they are organized in the bitmap: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * /- uptodate_offset /- dirty_offset /- ordered_offset 1762306a36Sopenharmony_ci * | | | 1862306a36Sopenharmony_ci * v v v 1962306a36Sopenharmony_ci * |u|u|u|u|........|u|u|d|d|.......|d|d|o|o|.......|o|o| 2062306a36Sopenharmony_ci * |<- bitmap_nr_bits ->| 2162306a36Sopenharmony_ci * |<----------------- total_nr_bits ------------------>| 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistruct btrfs_subpage_info { 2462306a36Sopenharmony_ci /* Number of bits for each bitmap */ 2562306a36Sopenharmony_ci unsigned int bitmap_nr_bits; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci /* Total number of bits for the whole bitmap */ 2862306a36Sopenharmony_ci unsigned int total_nr_bits; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* 3162306a36Sopenharmony_ci * *_start indicates where the bitmap starts, the length is always 3262306a36Sopenharmony_ci * @bitmap_size, which is calculated from PAGE_SIZE / sectorsize. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci unsigned int uptodate_offset; 3562306a36Sopenharmony_ci unsigned int dirty_offset; 3662306a36Sopenharmony_ci unsigned int writeback_offset; 3762306a36Sopenharmony_ci unsigned int ordered_offset; 3862306a36Sopenharmony_ci unsigned int checked_offset; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Structure to trace status of each sector inside a page, attached to 4362306a36Sopenharmony_ci * page::private for both data and metadata inodes. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistruct btrfs_subpage { 4662306a36Sopenharmony_ci /* Common members for both data and metadata pages */ 4762306a36Sopenharmony_ci spinlock_t lock; 4862306a36Sopenharmony_ci /* 4962306a36Sopenharmony_ci * Both data and metadata needs to track how many readers are for the 5062306a36Sopenharmony_ci * page. 5162306a36Sopenharmony_ci * Data relies on @readers to unlock the page when last reader finished. 5262306a36Sopenharmony_ci * While metadata doesn't need page unlock, it needs to prevent 5362306a36Sopenharmony_ci * page::private get cleared before the last end_page_read(). 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci atomic_t readers; 5662306a36Sopenharmony_ci union { 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * Structures only used by metadata 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * @eb_refs should only be operated under private_lock, as it 6162306a36Sopenharmony_ci * manages whether the subpage can be detached. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci atomic_t eb_refs; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Structures only used by data */ 6662306a36Sopenharmony_ci atomic_t writers; 6762306a36Sopenharmony_ci }; 6862306a36Sopenharmony_ci unsigned long bitmaps[]; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cienum btrfs_subpage_type { 7262306a36Sopenharmony_ci BTRFS_SUBPAGE_METADATA, 7362306a36Sopenharmony_ci BTRFS_SUBPAGE_DATA, 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cibool btrfs_is_subpage(const struct btrfs_fs_info *fs_info, struct page *page); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid btrfs_init_subpage_info(struct btrfs_subpage_info *subpage_info, u32 sectorsize); 7962306a36Sopenharmony_ciint btrfs_attach_subpage(const struct btrfs_fs_info *fs_info, 8062306a36Sopenharmony_ci struct page *page, enum btrfs_subpage_type type); 8162306a36Sopenharmony_civoid btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, 8262306a36Sopenharmony_ci struct page *page); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Allocate additional data where page represents more than one sector */ 8562306a36Sopenharmony_cistruct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info, 8662306a36Sopenharmony_ci enum btrfs_subpage_type type); 8762306a36Sopenharmony_civoid btrfs_free_subpage(struct btrfs_subpage *subpage); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_civoid btrfs_page_inc_eb_refs(const struct btrfs_fs_info *fs_info, 9062306a36Sopenharmony_ci struct page *page); 9162306a36Sopenharmony_civoid btrfs_page_dec_eb_refs(const struct btrfs_fs_info *fs_info, 9262306a36Sopenharmony_ci struct page *page); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_civoid btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info, 9562306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 9662306a36Sopenharmony_civoid btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info, 9762306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_civoid btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info, 10062306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 10162306a36Sopenharmony_cibool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info, 10262306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 10362306a36Sopenharmony_ciint btrfs_page_start_writer_lock(const struct btrfs_fs_info *fs_info, 10462306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 10562306a36Sopenharmony_civoid btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info, 10662306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * Template for subpage related operations. 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * btrfs_subpage_*() are for call sites where the page has subpage attached and 11262306a36Sopenharmony_ci * the range is ensured to be inside the page. 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * btrfs_page_*() are for call sites where the page can either be subpage 11562306a36Sopenharmony_ci * specific or regular page. The function will handle both cases. 11662306a36Sopenharmony_ci * But the range still needs to be inside the page. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * btrfs_page_clamp_*() are similar to btrfs_page_*(), except the range doesn't 11962306a36Sopenharmony_ci * need to be inside the page. Those functions will truncate the range 12062306a36Sopenharmony_ci * automatically. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci#define DECLARE_BTRFS_SUBPAGE_OPS(name) \ 12362306a36Sopenharmony_civoid btrfs_subpage_set_##name(const struct btrfs_fs_info *fs_info, \ 12462306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 12562306a36Sopenharmony_civoid btrfs_subpage_clear_##name(const struct btrfs_fs_info *fs_info, \ 12662306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 12762306a36Sopenharmony_cibool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info, \ 12862306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 12962306a36Sopenharmony_civoid btrfs_page_set_##name(const struct btrfs_fs_info *fs_info, \ 13062306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 13162306a36Sopenharmony_civoid btrfs_page_clear_##name(const struct btrfs_fs_info *fs_info, \ 13262306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 13362306a36Sopenharmony_cibool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info, \ 13462306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 13562306a36Sopenharmony_civoid btrfs_page_clamp_set_##name(const struct btrfs_fs_info *fs_info, \ 13662306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 13762306a36Sopenharmony_civoid btrfs_page_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \ 13862306a36Sopenharmony_ci struct page *page, u64 start, u32 len); \ 13962306a36Sopenharmony_cibool btrfs_page_clamp_test_##name(const struct btrfs_fs_info *fs_info, \ 14062306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ciDECLARE_BTRFS_SUBPAGE_OPS(uptodate); 14362306a36Sopenharmony_ciDECLARE_BTRFS_SUBPAGE_OPS(dirty); 14462306a36Sopenharmony_ciDECLARE_BTRFS_SUBPAGE_OPS(writeback); 14562306a36Sopenharmony_ciDECLARE_BTRFS_SUBPAGE_OPS(ordered); 14662306a36Sopenharmony_ciDECLARE_BTRFS_SUBPAGE_OPS(checked); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cibool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info, 14962306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_civoid btrfs_page_assert_not_dirty(const struct btrfs_fs_info *fs_info, 15262306a36Sopenharmony_ci struct page *page); 15362306a36Sopenharmony_civoid btrfs_page_unlock_writer(struct btrfs_fs_info *fs_info, struct page *page, 15462306a36Sopenharmony_ci u64 start, u32 len); 15562306a36Sopenharmony_civoid __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info, 15662306a36Sopenharmony_ci struct page *page, u64 start, u32 len); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#endif 159