xref: /openbmc/linux/fs/btrfs/subpage.c (revision 92082d40)
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);
558ff8466dSQu Wenruo 	if (type == BTRFS_SUBPAGE_METADATA)
568ff8466dSQu Wenruo 		atomic_set(&(*ret)->eb_refs, 0);
57*92082d40SQu Wenruo 	else
58*92082d40SQu Wenruo 		atomic_set(&(*ret)->readers, 0);
59760f991fSQu Wenruo 	return 0;
60760f991fSQu Wenruo }
61760f991fSQu Wenruo 
62760f991fSQu Wenruo void btrfs_free_subpage(struct btrfs_subpage *subpage)
63760f991fSQu Wenruo {
64cac06d84SQu Wenruo 	kfree(subpage);
65cac06d84SQu Wenruo }
668ff8466dSQu Wenruo 
678ff8466dSQu Wenruo /*
688ff8466dSQu Wenruo  * Increase the eb_refs of current subpage.
698ff8466dSQu Wenruo  *
708ff8466dSQu Wenruo  * This is important for eb allocation, to prevent race with last eb freeing
718ff8466dSQu Wenruo  * of the same page.
728ff8466dSQu Wenruo  * With the eb_refs increased before the eb inserted into radix tree,
738ff8466dSQu Wenruo  * detach_extent_buffer_page() won't detach the page private while we're still
748ff8466dSQu Wenruo  * allocating the extent buffer.
758ff8466dSQu Wenruo  */
768ff8466dSQu Wenruo void btrfs_page_inc_eb_refs(const struct btrfs_fs_info *fs_info,
778ff8466dSQu Wenruo 			    struct page *page)
788ff8466dSQu Wenruo {
798ff8466dSQu Wenruo 	struct btrfs_subpage *subpage;
808ff8466dSQu Wenruo 
818ff8466dSQu Wenruo 	if (fs_info->sectorsize == PAGE_SIZE)
828ff8466dSQu Wenruo 		return;
838ff8466dSQu Wenruo 
848ff8466dSQu Wenruo 	ASSERT(PagePrivate(page) && page->mapping);
858ff8466dSQu Wenruo 	lockdep_assert_held(&page->mapping->private_lock);
868ff8466dSQu Wenruo 
878ff8466dSQu Wenruo 	subpage = (struct btrfs_subpage *)page->private;
888ff8466dSQu Wenruo 	atomic_inc(&subpage->eb_refs);
898ff8466dSQu Wenruo }
908ff8466dSQu Wenruo 
918ff8466dSQu Wenruo void btrfs_page_dec_eb_refs(const struct btrfs_fs_info *fs_info,
928ff8466dSQu Wenruo 			    struct page *page)
938ff8466dSQu Wenruo {
948ff8466dSQu Wenruo 	struct btrfs_subpage *subpage;
958ff8466dSQu Wenruo 
968ff8466dSQu Wenruo 	if (fs_info->sectorsize == PAGE_SIZE)
978ff8466dSQu Wenruo 		return;
988ff8466dSQu Wenruo 
998ff8466dSQu Wenruo 	ASSERT(PagePrivate(page) && page->mapping);
1008ff8466dSQu Wenruo 	lockdep_assert_held(&page->mapping->private_lock);
1018ff8466dSQu Wenruo 
1028ff8466dSQu Wenruo 	subpage = (struct btrfs_subpage *)page->private;
1038ff8466dSQu Wenruo 	ASSERT(atomic_read(&subpage->eb_refs));
1048ff8466dSQu Wenruo 	atomic_dec(&subpage->eb_refs);
1058ff8466dSQu Wenruo }
106a1d767c1SQu Wenruo 
107*92082d40SQu Wenruo static void btrfs_subpage_assert(const struct btrfs_fs_info *fs_info,
108*92082d40SQu Wenruo 		struct page *page, u64 start, u32 len)
109*92082d40SQu Wenruo {
110*92082d40SQu Wenruo 	/* Basic checks */
111*92082d40SQu Wenruo 	ASSERT(PagePrivate(page) && page->private);
112*92082d40SQu Wenruo 	ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
113*92082d40SQu Wenruo 	       IS_ALIGNED(len, fs_info->sectorsize));
114*92082d40SQu Wenruo 	/*
115*92082d40SQu Wenruo 	 * The range check only works for mapped page, we can still have
116*92082d40SQu Wenruo 	 * unmapped page like dummy extent buffer pages.
117*92082d40SQu Wenruo 	 */
118*92082d40SQu Wenruo 	if (page->mapping)
119*92082d40SQu Wenruo 		ASSERT(page_offset(page) <= start &&
120*92082d40SQu Wenruo 		       start + len <= page_offset(page) + PAGE_SIZE);
121*92082d40SQu Wenruo }
122*92082d40SQu Wenruo 
123*92082d40SQu Wenruo void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info,
124*92082d40SQu Wenruo 		struct page *page, u64 start, u32 len)
125*92082d40SQu Wenruo {
126*92082d40SQu Wenruo 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
127*92082d40SQu Wenruo 	const int nbits = len >> fs_info->sectorsize_bits;
128*92082d40SQu Wenruo 	int ret;
129*92082d40SQu Wenruo 
130*92082d40SQu Wenruo 	btrfs_subpage_assert(fs_info, page, start, len);
131*92082d40SQu Wenruo 
132*92082d40SQu Wenruo 	ret = atomic_add_return(nbits, &subpage->readers);
133*92082d40SQu Wenruo 	ASSERT(ret == nbits);
134*92082d40SQu Wenruo }
135*92082d40SQu Wenruo 
136*92082d40SQu Wenruo void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
137*92082d40SQu Wenruo 		struct page *page, u64 start, u32 len)
138*92082d40SQu Wenruo {
139*92082d40SQu Wenruo 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
140*92082d40SQu Wenruo 	const int nbits = len >> fs_info->sectorsize_bits;
141*92082d40SQu Wenruo 
142*92082d40SQu Wenruo 	btrfs_subpage_assert(fs_info, page, start, len);
143*92082d40SQu Wenruo 	ASSERT(atomic_read(&subpage->readers) >= nbits);
144*92082d40SQu Wenruo 	if (atomic_sub_and_test(nbits, &subpage->readers))
145*92082d40SQu Wenruo 		unlock_page(page);
146*92082d40SQu Wenruo }
147*92082d40SQu Wenruo 
148a1d767c1SQu Wenruo /*
149a1d767c1SQu Wenruo  * Convert the [start, start + len) range into a u16 bitmap
150a1d767c1SQu Wenruo  *
151a1d767c1SQu Wenruo  * For example: if start == page_offset() + 16K, len = 16K, we get 0x00f0.
152a1d767c1SQu Wenruo  */
153a1d767c1SQu Wenruo static u16 btrfs_subpage_calc_bitmap(const struct btrfs_fs_info *fs_info,
154a1d767c1SQu Wenruo 		struct page *page, u64 start, u32 len)
155a1d767c1SQu Wenruo {
156a1d767c1SQu Wenruo 	const int bit_start = offset_in_page(start) >> fs_info->sectorsize_bits;
157a1d767c1SQu Wenruo 	const int nbits = len >> fs_info->sectorsize_bits;
158a1d767c1SQu Wenruo 
159*92082d40SQu Wenruo 	btrfs_subpage_assert(fs_info, page, start, len);
160a1d767c1SQu Wenruo 
161a1d767c1SQu Wenruo 	/*
162a1d767c1SQu Wenruo 	 * Here nbits can be 16, thus can go beyond u16 range. We make the
163a1d767c1SQu Wenruo 	 * first left shift to be calculate in unsigned long (at least u32),
164a1d767c1SQu Wenruo 	 * then truncate the result to u16.
165a1d767c1SQu Wenruo 	 */
166a1d767c1SQu Wenruo 	return (u16)(((1UL << nbits) - 1) << bit_start);
167a1d767c1SQu Wenruo }
168a1d767c1SQu Wenruo 
169a1d767c1SQu Wenruo void btrfs_subpage_set_uptodate(const struct btrfs_fs_info *fs_info,
170a1d767c1SQu Wenruo 		struct page *page, u64 start, u32 len)
171a1d767c1SQu Wenruo {
172a1d767c1SQu Wenruo 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
173a1d767c1SQu Wenruo 	const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
174a1d767c1SQu Wenruo 	unsigned long flags;
175a1d767c1SQu Wenruo 
176a1d767c1SQu Wenruo 	spin_lock_irqsave(&subpage->lock, flags);
177a1d767c1SQu Wenruo 	subpage->uptodate_bitmap |= tmp;
178a1d767c1SQu Wenruo 	if (subpage->uptodate_bitmap == U16_MAX)
179a1d767c1SQu Wenruo 		SetPageUptodate(page);
180a1d767c1SQu Wenruo 	spin_unlock_irqrestore(&subpage->lock, flags);
181a1d767c1SQu Wenruo }
182a1d767c1SQu Wenruo 
183a1d767c1SQu Wenruo void btrfs_subpage_clear_uptodate(const struct btrfs_fs_info *fs_info,
184a1d767c1SQu Wenruo 		struct page *page, u64 start, u32 len)
185a1d767c1SQu Wenruo {
186a1d767c1SQu Wenruo 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
187a1d767c1SQu Wenruo 	const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
188a1d767c1SQu Wenruo 	unsigned long flags;
189a1d767c1SQu Wenruo 
190a1d767c1SQu Wenruo 	spin_lock_irqsave(&subpage->lock, flags);
191a1d767c1SQu Wenruo 	subpage->uptodate_bitmap &= ~tmp;
192a1d767c1SQu Wenruo 	ClearPageUptodate(page);
193a1d767c1SQu Wenruo 	spin_unlock_irqrestore(&subpage->lock, flags);
194a1d767c1SQu Wenruo }
195a1d767c1SQu Wenruo 
19603a816b3SQu Wenruo void btrfs_subpage_set_error(const struct btrfs_fs_info *fs_info,
19703a816b3SQu Wenruo 		struct page *page, u64 start, u32 len)
19803a816b3SQu Wenruo {
19903a816b3SQu Wenruo 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
20003a816b3SQu Wenruo 	const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
20103a816b3SQu Wenruo 	unsigned long flags;
20203a816b3SQu Wenruo 
20303a816b3SQu Wenruo 	spin_lock_irqsave(&subpage->lock, flags);
20403a816b3SQu Wenruo 	subpage->error_bitmap |= tmp;
20503a816b3SQu Wenruo 	SetPageError(page);
20603a816b3SQu Wenruo 	spin_unlock_irqrestore(&subpage->lock, flags);
20703a816b3SQu Wenruo }
20803a816b3SQu Wenruo 
20903a816b3SQu Wenruo void btrfs_subpage_clear_error(const struct btrfs_fs_info *fs_info,
21003a816b3SQu Wenruo 		struct page *page, u64 start, u32 len)
21103a816b3SQu Wenruo {
21203a816b3SQu Wenruo 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
21303a816b3SQu Wenruo 	const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
21403a816b3SQu Wenruo 	unsigned long flags;
21503a816b3SQu Wenruo 
21603a816b3SQu Wenruo 	spin_lock_irqsave(&subpage->lock, flags);
21703a816b3SQu Wenruo 	subpage->error_bitmap &= ~tmp;
21803a816b3SQu Wenruo 	if (subpage->error_bitmap == 0)
21903a816b3SQu Wenruo 		ClearPageError(page);
22003a816b3SQu Wenruo 	spin_unlock_irqrestore(&subpage->lock, flags);
22103a816b3SQu Wenruo }
22203a816b3SQu Wenruo 
223a1d767c1SQu Wenruo /*
224a1d767c1SQu Wenruo  * Unlike set/clear which is dependent on each page status, for test all bits
225a1d767c1SQu Wenruo  * are tested in the same way.
226a1d767c1SQu Wenruo  */
227a1d767c1SQu Wenruo #define IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(name)				\
228a1d767c1SQu Wenruo bool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info,	\
229a1d767c1SQu Wenruo 		struct page *page, u64 start, u32 len)			\
230a1d767c1SQu Wenruo {									\
231a1d767c1SQu Wenruo 	struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private; \
232a1d767c1SQu Wenruo 	const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len); \
233a1d767c1SQu Wenruo 	unsigned long flags;						\
234a1d767c1SQu Wenruo 	bool ret;							\
235a1d767c1SQu Wenruo 									\
236a1d767c1SQu Wenruo 	spin_lock_irqsave(&subpage->lock, flags);			\
237a1d767c1SQu Wenruo 	ret = ((subpage->name##_bitmap & tmp) == tmp);			\
238a1d767c1SQu Wenruo 	spin_unlock_irqrestore(&subpage->lock, flags);			\
239a1d767c1SQu Wenruo 	return ret;							\
240a1d767c1SQu Wenruo }
241a1d767c1SQu Wenruo IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(uptodate);
24203a816b3SQu Wenruo IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(error);
243a1d767c1SQu Wenruo 
244a1d767c1SQu Wenruo /*
245a1d767c1SQu Wenruo  * Note that, in selftests (extent-io-tests), we can have empty fs_info passed
246a1d767c1SQu Wenruo  * in.  We only test sectorsize == PAGE_SIZE cases so far, thus we can fall
247a1d767c1SQu Wenruo  * back to regular sectorsize branch.
248a1d767c1SQu Wenruo  */
249a1d767c1SQu Wenruo #define IMPLEMENT_BTRFS_PAGE_OPS(name, set_page_func, clear_page_func,	\
250a1d767c1SQu Wenruo 			       test_page_func)				\
251a1d767c1SQu Wenruo void btrfs_page_set_##name(const struct btrfs_fs_info *fs_info,		\
252a1d767c1SQu Wenruo 		struct page *page, u64 start, u32 len)			\
253a1d767c1SQu Wenruo {									\
254a1d767c1SQu Wenruo 	if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {	\
255a1d767c1SQu Wenruo 		set_page_func(page);					\
256a1d767c1SQu Wenruo 		return;							\
257a1d767c1SQu Wenruo 	}								\
258a1d767c1SQu Wenruo 	btrfs_subpage_set_##name(fs_info, page, start, len);		\
259a1d767c1SQu Wenruo }									\
260a1d767c1SQu Wenruo void btrfs_page_clear_##name(const struct btrfs_fs_info *fs_info,	\
261a1d767c1SQu Wenruo 		struct page *page, u64 start, u32 len)			\
262a1d767c1SQu Wenruo {									\
263a1d767c1SQu Wenruo 	if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {	\
264a1d767c1SQu Wenruo 		clear_page_func(page);					\
265a1d767c1SQu Wenruo 		return;							\
266a1d767c1SQu Wenruo 	}								\
267a1d767c1SQu Wenruo 	btrfs_subpage_clear_##name(fs_info, page, start, len);		\
268a1d767c1SQu Wenruo }									\
269a1d767c1SQu Wenruo bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info,	\
270a1d767c1SQu Wenruo 		struct page *page, u64 start, u32 len)			\
271a1d767c1SQu Wenruo {									\
272a1d767c1SQu Wenruo 	if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE)	\
273a1d767c1SQu Wenruo 		return test_page_func(page);				\
274a1d767c1SQu Wenruo 	return btrfs_subpage_test_##name(fs_info, page, start, len);	\
275a1d767c1SQu Wenruo }
276a1d767c1SQu Wenruo IMPLEMENT_BTRFS_PAGE_OPS(uptodate, SetPageUptodate, ClearPageUptodate,
277a1d767c1SQu Wenruo 			 PageUptodate);
27803a816b3SQu Wenruo IMPLEMENT_BTRFS_PAGE_OPS(error, SetPageError, ClearPageError, PageError);
279