xref: /openbmc/linux/fs/btrfs/subpage.c (revision 8ff8466d)
1cac06d84SQu Wenruo // SPDX-License-Identifier: GPL-2.0
2cac06d84SQu Wenruo 
3cac06d84SQu Wenruo #include <linux/slab.h>
4cac06d84SQu Wenruo #include "ctree.h"
5cac06d84SQu Wenruo #include "subpage.h"
6cac06d84SQu Wenruo 
7cac06d84SQu Wenruo int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
8cac06d84SQu Wenruo 			 struct page *page, enum btrfs_subpage_type type)
9cac06d84SQu Wenruo {
10760f991fSQu Wenruo 	struct btrfs_subpage *subpage = NULL;
11760f991fSQu Wenruo 	int ret;
12cac06d84SQu Wenruo 
13cac06d84SQu Wenruo 	/*
14cac06d84SQu Wenruo 	 * We have cases like a dummy extent buffer page, which is not mappped
15cac06d84SQu Wenruo 	 * and doesn't need to be locked.
16cac06d84SQu Wenruo 	 */
17cac06d84SQu Wenruo 	if (page->mapping)
18cac06d84SQu Wenruo 		ASSERT(PageLocked(page));
19cac06d84SQu Wenruo 	/* Either not subpage, or the page already has private attached */
20cac06d84SQu Wenruo 	if (fs_info->sectorsize == PAGE_SIZE || PagePrivate(page))
21cac06d84SQu Wenruo 		return 0;
22cac06d84SQu Wenruo 
23760f991fSQu Wenruo 	ret = btrfs_alloc_subpage(fs_info, &subpage, type);
24760f991fSQu Wenruo 	if (ret < 0)
25760f991fSQu Wenruo 		return ret;
26cac06d84SQu Wenruo 	attach_page_private(page, subpage);
27cac06d84SQu Wenruo 	return 0;
28cac06d84SQu Wenruo }
29cac06d84SQu Wenruo 
30cac06d84SQu Wenruo void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info,
31cac06d84SQu Wenruo 			  struct page *page)
32cac06d84SQu Wenruo {
33cac06d84SQu Wenruo 	struct btrfs_subpage *subpage;
34cac06d84SQu Wenruo 
35cac06d84SQu Wenruo 	/* Either not subpage, or already detached */
36cac06d84SQu Wenruo 	if (fs_info->sectorsize == PAGE_SIZE || !PagePrivate(page))
37cac06d84SQu Wenruo 		return;
38cac06d84SQu Wenruo 
39cac06d84SQu Wenruo 	subpage = (struct btrfs_subpage *)detach_page_private(page);
40cac06d84SQu Wenruo 	ASSERT(subpage);
41760f991fSQu Wenruo 	btrfs_free_subpage(subpage);
42760f991fSQu Wenruo }
43760f991fSQu Wenruo 
44760f991fSQu Wenruo int btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,
45760f991fSQu Wenruo 			struct btrfs_subpage **ret,
46760f991fSQu Wenruo 			enum btrfs_subpage_type type)
47760f991fSQu Wenruo {
48760f991fSQu Wenruo 	if (fs_info->sectorsize == PAGE_SIZE)
49760f991fSQu Wenruo 		return 0;
50760f991fSQu Wenruo 
51760f991fSQu Wenruo 	*ret = kzalloc(sizeof(struct btrfs_subpage), GFP_NOFS);
52760f991fSQu Wenruo 	if (!*ret)
53760f991fSQu Wenruo 		return -ENOMEM;
54760f991fSQu Wenruo 	spin_lock_init(&(*ret)->lock);
55*8ff8466dSQu Wenruo 	if (type == BTRFS_SUBPAGE_METADATA)
56*8ff8466dSQu Wenruo 		atomic_set(&(*ret)->eb_refs, 0);
57760f991fSQu Wenruo 	return 0;
58760f991fSQu Wenruo }
59760f991fSQu Wenruo 
60760f991fSQu Wenruo void btrfs_free_subpage(struct btrfs_subpage *subpage)
61760f991fSQu Wenruo {
62cac06d84SQu Wenruo 	kfree(subpage);
63cac06d84SQu Wenruo }
64*8ff8466dSQu Wenruo 
65*8ff8466dSQu Wenruo /*
66*8ff8466dSQu Wenruo  * Increase the eb_refs of current subpage.
67*8ff8466dSQu Wenruo  *
68*8ff8466dSQu Wenruo  * This is important for eb allocation, to prevent race with last eb freeing
69*8ff8466dSQu Wenruo  * of the same page.
70*8ff8466dSQu Wenruo  * With the eb_refs increased before the eb inserted into radix tree,
71*8ff8466dSQu Wenruo  * detach_extent_buffer_page() won't detach the page private while we're still
72*8ff8466dSQu Wenruo  * allocating the extent buffer.
73*8ff8466dSQu Wenruo  */
74*8ff8466dSQu Wenruo void btrfs_page_inc_eb_refs(const struct btrfs_fs_info *fs_info,
75*8ff8466dSQu Wenruo 			    struct page *page)
76*8ff8466dSQu Wenruo {
77*8ff8466dSQu Wenruo 	struct btrfs_subpage *subpage;
78*8ff8466dSQu Wenruo 
79*8ff8466dSQu Wenruo 	if (fs_info->sectorsize == PAGE_SIZE)
80*8ff8466dSQu Wenruo 		return;
81*8ff8466dSQu Wenruo 
82*8ff8466dSQu Wenruo 	ASSERT(PagePrivate(page) && page->mapping);
83*8ff8466dSQu Wenruo 	lockdep_assert_held(&page->mapping->private_lock);
84*8ff8466dSQu Wenruo 
85*8ff8466dSQu Wenruo 	subpage = (struct btrfs_subpage *)page->private;
86*8ff8466dSQu Wenruo 	atomic_inc(&subpage->eb_refs);
87*8ff8466dSQu Wenruo }
88*8ff8466dSQu Wenruo 
89*8ff8466dSQu Wenruo void btrfs_page_dec_eb_refs(const struct btrfs_fs_info *fs_info,
90*8ff8466dSQu Wenruo 			    struct page *page)
91*8ff8466dSQu Wenruo {
92*8ff8466dSQu Wenruo 	struct btrfs_subpage *subpage;
93*8ff8466dSQu Wenruo 
94*8ff8466dSQu Wenruo 	if (fs_info->sectorsize == PAGE_SIZE)
95*8ff8466dSQu Wenruo 		return;
96*8ff8466dSQu Wenruo 
97*8ff8466dSQu Wenruo 	ASSERT(PagePrivate(page) && page->mapping);
98*8ff8466dSQu Wenruo 	lockdep_assert_held(&page->mapping->private_lock);
99*8ff8466dSQu Wenruo 
100*8ff8466dSQu Wenruo 	subpage = (struct btrfs_subpage *)page->private;
101*8ff8466dSQu Wenruo 	ASSERT(atomic_read(&subpage->eb_refs));
102*8ff8466dSQu Wenruo 	atomic_dec(&subpage->eb_refs);
103*8ff8466dSQu Wenruo }
104