xref: /OK3568_Linux_fs/kernel/fs/btrfs/struct-funcs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2007 Oracle.  All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <asm/unaligned.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "ctree.h"
9*4882a593Smuzhiyun 
check_setget_bounds(const struct extent_buffer * eb,const void * ptr,unsigned off,int size)10*4882a593Smuzhiyun static bool check_setget_bounds(const struct extent_buffer *eb,
11*4882a593Smuzhiyun 				const void *ptr, unsigned off, int size)
12*4882a593Smuzhiyun {
13*4882a593Smuzhiyun 	const unsigned long member_offset = (unsigned long)ptr + off;
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun 	if (member_offset > eb->len) {
16*4882a593Smuzhiyun 		btrfs_warn(eb->fs_info,
17*4882a593Smuzhiyun 	"bad eb member start: ptr 0x%lx start %llu member offset %lu size %d",
18*4882a593Smuzhiyun 			(unsigned long)ptr, eb->start, member_offset, size);
19*4882a593Smuzhiyun 		return false;
20*4882a593Smuzhiyun 	}
21*4882a593Smuzhiyun 	if (member_offset + size > eb->len) {
22*4882a593Smuzhiyun 		btrfs_warn(eb->fs_info,
23*4882a593Smuzhiyun 	"bad eb member end: ptr 0x%lx start %llu member offset %lu size %d",
24*4882a593Smuzhiyun 			(unsigned long)ptr, eb->start, member_offset, size);
25*4882a593Smuzhiyun 		return false;
26*4882a593Smuzhiyun 	}
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	return true;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  * Macro templates that define helpers to read/write extent buffer data of a
33*4882a593Smuzhiyun  * given size, that are also used via ctree.h for access to item members by
34*4882a593Smuzhiyun  * specialized helpers.
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * Generic helpers:
37*4882a593Smuzhiyun  * - btrfs_set_8 (for 8/16/32/64)
38*4882a593Smuzhiyun  * - btrfs_get_8 (for 8/16/32/64)
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * Generic helpers with a token (cached address of the most recently accessed
41*4882a593Smuzhiyun  * page):
42*4882a593Smuzhiyun  * - btrfs_set_token_8 (for 8/16/32/64)
43*4882a593Smuzhiyun  * - btrfs_get_token_8 (for 8/16/32/64)
44*4882a593Smuzhiyun  *
45*4882a593Smuzhiyun  * The set/get functions handle data spanning two pages transparently, in case
46*4882a593Smuzhiyun  * metadata block size is larger than page.  Every pointer to metadata items is
47*4882a593Smuzhiyun  * an offset into the extent buffer page array, cast to a specific type.  This
48*4882a593Smuzhiyun  * gives us all the type checking.
49*4882a593Smuzhiyun  *
50*4882a593Smuzhiyun  * The extent buffer pages stored in the array pages do not form a contiguous
51*4882a593Smuzhiyun  * phyusical range, but the API functions assume the linear offset to the range
52*4882a593Smuzhiyun  * from 0 to metadata node size.
53*4882a593Smuzhiyun  */
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define DEFINE_BTRFS_SETGET_BITS(bits)					\
56*4882a593Smuzhiyun u##bits btrfs_get_token_##bits(struct btrfs_map_token *token,		\
57*4882a593Smuzhiyun 			       const void *ptr, unsigned long off)	\
58*4882a593Smuzhiyun {									\
59*4882a593Smuzhiyun 	const unsigned long member_offset = (unsigned long)ptr + off;	\
60*4882a593Smuzhiyun 	const unsigned long idx = member_offset >> PAGE_SHIFT;		\
61*4882a593Smuzhiyun 	const unsigned long oip = offset_in_page(member_offset);	\
62*4882a593Smuzhiyun 	const int size = sizeof(u##bits);				\
63*4882a593Smuzhiyun 	u8 lebytes[sizeof(u##bits)];					\
64*4882a593Smuzhiyun 	const int part = PAGE_SIZE - oip;				\
65*4882a593Smuzhiyun 									\
66*4882a593Smuzhiyun 	ASSERT(token);							\
67*4882a593Smuzhiyun 	ASSERT(token->kaddr);						\
68*4882a593Smuzhiyun 	ASSERT(check_setget_bounds(token->eb, ptr, off, size));		\
69*4882a593Smuzhiyun 	if (token->offset <= member_offset &&				\
70*4882a593Smuzhiyun 	    member_offset + size <= token->offset + PAGE_SIZE) {	\
71*4882a593Smuzhiyun 		return get_unaligned_le##bits(token->kaddr + oip);	\
72*4882a593Smuzhiyun 	}								\
73*4882a593Smuzhiyun 	token->kaddr = page_address(token->eb->pages[idx]);		\
74*4882a593Smuzhiyun 	token->offset = idx << PAGE_SHIFT;				\
75*4882a593Smuzhiyun 	if (oip + size <= PAGE_SIZE)					\
76*4882a593Smuzhiyun 		return get_unaligned_le##bits(token->kaddr + oip);	\
77*4882a593Smuzhiyun 									\
78*4882a593Smuzhiyun 	memcpy(lebytes, token->kaddr + oip, part);			\
79*4882a593Smuzhiyun 	token->kaddr = page_address(token->eb->pages[idx + 1]);		\
80*4882a593Smuzhiyun 	token->offset = (idx + 1) << PAGE_SHIFT;			\
81*4882a593Smuzhiyun 	memcpy(lebytes + part, token->kaddr, size - part);		\
82*4882a593Smuzhiyun 	return get_unaligned_le##bits(lebytes);				\
83*4882a593Smuzhiyun }									\
84*4882a593Smuzhiyun u##bits btrfs_get_##bits(const struct extent_buffer *eb,		\
85*4882a593Smuzhiyun 			 const void *ptr, unsigned long off)		\
86*4882a593Smuzhiyun {									\
87*4882a593Smuzhiyun 	const unsigned long member_offset = (unsigned long)ptr + off;	\
88*4882a593Smuzhiyun 	const unsigned long oip = offset_in_page(member_offset);	\
89*4882a593Smuzhiyun 	const unsigned long idx = member_offset >> PAGE_SHIFT;		\
90*4882a593Smuzhiyun 	char *kaddr = page_address(eb->pages[idx]);			\
91*4882a593Smuzhiyun 	const int size = sizeof(u##bits);				\
92*4882a593Smuzhiyun 	const int part = PAGE_SIZE - oip;				\
93*4882a593Smuzhiyun 	u8 lebytes[sizeof(u##bits)];					\
94*4882a593Smuzhiyun 									\
95*4882a593Smuzhiyun 	ASSERT(check_setget_bounds(eb, ptr, off, size));		\
96*4882a593Smuzhiyun 	if (oip + size <= PAGE_SIZE)					\
97*4882a593Smuzhiyun 		return get_unaligned_le##bits(kaddr + oip);		\
98*4882a593Smuzhiyun 									\
99*4882a593Smuzhiyun 	memcpy(lebytes, kaddr + oip, part);				\
100*4882a593Smuzhiyun 	kaddr = page_address(eb->pages[idx + 1]);			\
101*4882a593Smuzhiyun 	memcpy(lebytes + part, kaddr, size - part);			\
102*4882a593Smuzhiyun 	return get_unaligned_le##bits(lebytes);				\
103*4882a593Smuzhiyun }									\
104*4882a593Smuzhiyun void btrfs_set_token_##bits(struct btrfs_map_token *token,		\
105*4882a593Smuzhiyun 			    const void *ptr, unsigned long off,		\
106*4882a593Smuzhiyun 			    u##bits val)				\
107*4882a593Smuzhiyun {									\
108*4882a593Smuzhiyun 	const unsigned long member_offset = (unsigned long)ptr + off;	\
109*4882a593Smuzhiyun 	const unsigned long idx = member_offset >> PAGE_SHIFT;		\
110*4882a593Smuzhiyun 	const unsigned long oip = offset_in_page(member_offset);	\
111*4882a593Smuzhiyun 	const int size = sizeof(u##bits);				\
112*4882a593Smuzhiyun 	u8 lebytes[sizeof(u##bits)];					\
113*4882a593Smuzhiyun 	const int part = PAGE_SIZE - oip;				\
114*4882a593Smuzhiyun 									\
115*4882a593Smuzhiyun 	ASSERT(token);							\
116*4882a593Smuzhiyun 	ASSERT(token->kaddr);						\
117*4882a593Smuzhiyun 	ASSERT(check_setget_bounds(token->eb, ptr, off, size));		\
118*4882a593Smuzhiyun 	if (token->offset <= member_offset &&				\
119*4882a593Smuzhiyun 	    member_offset + size <= token->offset + PAGE_SIZE) {	\
120*4882a593Smuzhiyun 		put_unaligned_le##bits(val, token->kaddr + oip);	\
121*4882a593Smuzhiyun 		return;							\
122*4882a593Smuzhiyun 	}								\
123*4882a593Smuzhiyun 	token->kaddr = page_address(token->eb->pages[idx]);		\
124*4882a593Smuzhiyun 	token->offset = idx << PAGE_SHIFT;				\
125*4882a593Smuzhiyun 	if (oip + size <= PAGE_SIZE) {					\
126*4882a593Smuzhiyun 		put_unaligned_le##bits(val, token->kaddr + oip);	\
127*4882a593Smuzhiyun 		return;							\
128*4882a593Smuzhiyun 	}								\
129*4882a593Smuzhiyun 	put_unaligned_le##bits(val, lebytes);				\
130*4882a593Smuzhiyun 	memcpy(token->kaddr + oip, lebytes, part);			\
131*4882a593Smuzhiyun 	token->kaddr = page_address(token->eb->pages[idx + 1]);		\
132*4882a593Smuzhiyun 	token->offset = (idx + 1) << PAGE_SHIFT;			\
133*4882a593Smuzhiyun 	memcpy(token->kaddr, lebytes + part, size - part);		\
134*4882a593Smuzhiyun }									\
135*4882a593Smuzhiyun void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr,	\
136*4882a593Smuzhiyun 		      unsigned long off, u##bits val)			\
137*4882a593Smuzhiyun {									\
138*4882a593Smuzhiyun 	const unsigned long member_offset = (unsigned long)ptr + off;	\
139*4882a593Smuzhiyun 	const unsigned long oip = offset_in_page(member_offset);	\
140*4882a593Smuzhiyun 	const unsigned long idx = member_offset >> PAGE_SHIFT;		\
141*4882a593Smuzhiyun 	char *kaddr = page_address(eb->pages[idx]);			\
142*4882a593Smuzhiyun 	const int size = sizeof(u##bits);				\
143*4882a593Smuzhiyun 	const int part = PAGE_SIZE - oip;				\
144*4882a593Smuzhiyun 	u8 lebytes[sizeof(u##bits)];					\
145*4882a593Smuzhiyun 									\
146*4882a593Smuzhiyun 	ASSERT(check_setget_bounds(eb, ptr, off, size));		\
147*4882a593Smuzhiyun 	if (oip + size <= PAGE_SIZE) {					\
148*4882a593Smuzhiyun 		put_unaligned_le##bits(val, kaddr + oip);		\
149*4882a593Smuzhiyun 		return;							\
150*4882a593Smuzhiyun 	}								\
151*4882a593Smuzhiyun 									\
152*4882a593Smuzhiyun 	put_unaligned_le##bits(val, lebytes);				\
153*4882a593Smuzhiyun 	memcpy(kaddr + oip, lebytes, part);				\
154*4882a593Smuzhiyun 	kaddr = page_address(eb->pages[idx + 1]);			\
155*4882a593Smuzhiyun 	memcpy(kaddr, lebytes + part, size - part);			\
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun DEFINE_BTRFS_SETGET_BITS(8)
159*4882a593Smuzhiyun DEFINE_BTRFS_SETGET_BITS(16)
160*4882a593Smuzhiyun DEFINE_BTRFS_SETGET_BITS(32)
161*4882a593Smuzhiyun DEFINE_BTRFS_SETGET_BITS(64)
162*4882a593Smuzhiyun 
btrfs_node_key(const struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)163*4882a593Smuzhiyun void btrfs_node_key(const struct extent_buffer *eb,
164*4882a593Smuzhiyun 		    struct btrfs_disk_key *disk_key, int nr)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
167*4882a593Smuzhiyun 	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
168*4882a593Smuzhiyun 		       struct btrfs_key_ptr, key, disk_key);
169*4882a593Smuzhiyun }
170