mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
4.5 KiB
129 lines
4.5 KiB
/* SPDX-License-Identifier: GPL-2.0 */ |
|
|
|
#ifndef BTRFS_SUBPAGE_H |
|
#define BTRFS_SUBPAGE_H |
|
|
|
#include <linux/spinlock.h> |
|
|
|
/* |
|
* Maximum page size we support is 64K, minimum sector size is 4K, u16 bitmap |
|
* is sufficient. Regular bitmap_* is not used due to size reasons. |
|
*/ |
|
#define BTRFS_SUBPAGE_BITMAP_SIZE 16 |
|
|
|
/* |
|
* Structure to trace status of each sector inside a page, attached to |
|
* page::private for both data and metadata inodes. |
|
*/ |
|
struct btrfs_subpage { |
|
/* Common members for both data and metadata pages */ |
|
spinlock_t lock; |
|
u16 uptodate_bitmap; |
|
u16 error_bitmap; |
|
u16 dirty_bitmap; |
|
u16 writeback_bitmap; |
|
/* |
|
* Both data and metadata needs to track how many readers are for the |
|
* page. |
|
* Data relies on @readers to unlock the page when last reader finished. |
|
* While metadata doesn't need page unlock, it needs to prevent |
|
* page::private get cleared before the last end_page_read(). |
|
*/ |
|
atomic_t readers; |
|
union { |
|
/* |
|
* Structures only used by metadata |
|
* |
|
* @eb_refs should only be operated under private_lock, as it |
|
* manages whether the subpage can be detached. |
|
*/ |
|
atomic_t eb_refs; |
|
/* Structures only used by data */ |
|
struct { |
|
atomic_t writers; |
|
|
|
/* Tracke pending ordered extent in this sector */ |
|
u16 ordered_bitmap; |
|
}; |
|
}; |
|
}; |
|
|
|
enum btrfs_subpage_type { |
|
BTRFS_SUBPAGE_METADATA, |
|
BTRFS_SUBPAGE_DATA, |
|
}; |
|
|
|
int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info, |
|
struct page *page, enum btrfs_subpage_type type); |
|
void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, |
|
struct page *page); |
|
|
|
/* Allocate additional data where page represents more than one sector */ |
|
int btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info, |
|
struct btrfs_subpage **ret, |
|
enum btrfs_subpage_type type); |
|
void btrfs_free_subpage(struct btrfs_subpage *subpage); |
|
|
|
void btrfs_page_inc_eb_refs(const struct btrfs_fs_info *fs_info, |
|
struct page *page); |
|
void btrfs_page_dec_eb_refs(const struct btrfs_fs_info *fs_info, |
|
struct page *page); |
|
|
|
void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info, |
|
struct page *page, u64 start, u32 len); |
|
void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info, |
|
struct page *page, u64 start, u32 len); |
|
|
|
void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info, |
|
struct page *page, u64 start, u32 len); |
|
bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info, |
|
struct page *page, u64 start, u32 len); |
|
int btrfs_page_start_writer_lock(const struct btrfs_fs_info *fs_info, |
|
struct page *page, u64 start, u32 len); |
|
void btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info, |
|
struct page *page, u64 start, u32 len); |
|
|
|
/* |
|
* Template for subpage related operations. |
|
* |
|
* btrfs_subpage_*() are for call sites where the page has subpage attached and |
|
* the range is ensured to be inside the page. |
|
* |
|
* btrfs_page_*() are for call sites where the page can either be subpage |
|
* specific or regular page. The function will handle both cases. |
|
* But the range still needs to be inside the page. |
|
* |
|
* btrfs_page_clamp_*() are similar to btrfs_page_*(), except the range doesn't |
|
* need to be inside the page. Those functions will truncate the range |
|
* automatically. |
|
*/ |
|
#define DECLARE_BTRFS_SUBPAGE_OPS(name) \ |
|
void btrfs_subpage_set_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
void btrfs_subpage_clear_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
bool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
void btrfs_page_set_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
void btrfs_page_clear_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
void btrfs_page_clamp_set_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
void btrfs_page_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); \ |
|
bool btrfs_page_clamp_test_##name(const struct btrfs_fs_info *fs_info, \ |
|
struct page *page, u64 start, u32 len); |
|
|
|
DECLARE_BTRFS_SUBPAGE_OPS(uptodate); |
|
DECLARE_BTRFS_SUBPAGE_OPS(error); |
|
DECLARE_BTRFS_SUBPAGE_OPS(dirty); |
|
DECLARE_BTRFS_SUBPAGE_OPS(writeback); |
|
DECLARE_BTRFS_SUBPAGE_OPS(ordered); |
|
|
|
bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info, |
|
struct page *page, u64 start, u32 len); |
|
|
|
#endif
|
|
|