• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Copyright (C) 2007 Oracle.  All rights reserved.
4   */
5  
6  #include <asm/unaligned.h>
7  
8  #include "ctree.h"
9  
get_unaligned_le8(const void * p)10  static inline u8 get_unaligned_le8(const void *p)
11  {
12         return *(u8 *)p;
13  }
14  
put_unaligned_le8(u8 val,void * p)15  static inline void put_unaligned_le8(u8 val, void *p)
16  {
17         *(u8 *)p = val;
18  }
19  
20  /*
21   * this is some deeply nasty code.
22   *
23   * The end result is that anyone who #includes ctree.h gets a
24   * declaration for the btrfs_set_foo functions and btrfs_foo functions,
25   * which are wrappers of btrfs_set_token_#bits functions and
26   * btrfs_get_token_#bits functions, which are defined in this file.
27   *
28   * These setget functions do all the extent_buffer related mapping
29   * required to efficiently read and write specific fields in the extent
30   * buffers.  Every pointer to metadata items in btrfs is really just
31   * an unsigned long offset into the extent buffer which has been
32   * cast to a specific type.  This gives us all the gcc type checking.
33   *
34   * The extent buffer api is used to do the page spanning work required to
35   * have a metadata blocksize different from the page size.
36   *
37   * There are 2 variants defined, one with a token pointer and one without.
38   */
39  
40  #define DEFINE_BTRFS_SETGET_BITS(bits)					\
41  u##bits btrfs_get_token_##bits(const struct extent_buffer *eb,		\
42  			       const void *ptr, unsigned long off,	\
43  			       struct btrfs_map_token *token)		\
44  {									\
45  	unsigned long part_offset = (unsigned long)ptr;			\
46  	unsigned long offset = part_offset + off;			\
47  	void *p;							\
48  	int err;							\
49  	char *kaddr;							\
50  	unsigned long map_start;					\
51  	unsigned long map_len;						\
52  	int size = sizeof(u##bits);					\
53  	u##bits res;							\
54  									\
55  	ASSERT(token);							\
56  	ASSERT(token->eb == eb);					\
57  									\
58  	if (token->kaddr && token->offset <= offset &&			\
59  	   (token->offset + PAGE_SIZE >= offset + size)) {	\
60  		kaddr = token->kaddr;					\
61  		p = kaddr + part_offset - token->offset;		\
62  		res = get_unaligned_le##bits(p + off);			\
63  		return res;						\
64  	}								\
65  	err = map_private_extent_buffer(eb, offset, size,		\
66  					&kaddr, &map_start, &map_len);	\
67  	if (err) {							\
68  		__le##bits leres;					\
69  									\
70  		read_extent_buffer(eb, &leres, offset, size);		\
71  		return le##bits##_to_cpu(leres);			\
72  	}								\
73  	p = kaddr + part_offset - map_start;				\
74  	res = get_unaligned_le##bits(p + off);				\
75  	token->kaddr = kaddr;						\
76  	token->offset = map_start;					\
77  	return res;							\
78  }									\
79  u##bits btrfs_get_##bits(const struct extent_buffer *eb,		\
80  			 const void *ptr, unsigned long off)		\
81  {									\
82  	unsigned long part_offset = (unsigned long)ptr;			\
83  	unsigned long offset = part_offset + off;			\
84  	void *p;							\
85  	int err;							\
86  	char *kaddr;							\
87  	unsigned long map_start;					\
88  	unsigned long map_len;						\
89  	int size = sizeof(u##bits);					\
90  	u##bits res;							\
91  									\
92  	err = map_private_extent_buffer(eb, offset, size,		\
93  					&kaddr, &map_start, &map_len);	\
94  	if (err) {							\
95  		__le##bits leres;					\
96  									\
97  		read_extent_buffer(eb, &leres, offset, size);		\
98  		return le##bits##_to_cpu(leres);			\
99  	}								\
100  	p = kaddr + part_offset - map_start;				\
101  	res = get_unaligned_le##bits(p + off);				\
102  	return res;							\
103  }									\
104  void btrfs_set_token_##bits(struct extent_buffer *eb,			\
105  			    const void *ptr, unsigned long off,		\
106  			    u##bits val,				\
107  			    struct btrfs_map_token *token)		\
108  {									\
109  	unsigned long part_offset = (unsigned long)ptr;			\
110  	unsigned long offset = part_offset + off;			\
111  	void *p;							\
112  	int err;							\
113  	char *kaddr;							\
114  	unsigned long map_start;					\
115  	unsigned long map_len;						\
116  	int size = sizeof(u##bits);					\
117  									\
118  	ASSERT(token);							\
119  	ASSERT(token->eb == eb);					\
120  									\
121  	if (token->kaddr && token->offset <= offset &&			\
122  	   (token->offset + PAGE_SIZE >= offset + size)) {	\
123  		kaddr = token->kaddr;					\
124  		p = kaddr + part_offset - token->offset;		\
125  		put_unaligned_le##bits(val, p + off);			\
126  		return;							\
127  	}								\
128  	err = map_private_extent_buffer(eb, offset, size,		\
129  			&kaddr, &map_start, &map_len);			\
130  	if (err) {							\
131  		__le##bits val2;					\
132  									\
133  		val2 = cpu_to_le##bits(val);				\
134  		write_extent_buffer(eb, &val2, offset, size);		\
135  		return;							\
136  	}								\
137  	p = kaddr + part_offset - map_start;				\
138  	put_unaligned_le##bits(val, p + off);				\
139  	token->kaddr = kaddr;						\
140  	token->offset = map_start;					\
141  }									\
142  void btrfs_set_##bits(struct extent_buffer *eb, void *ptr,		\
143  		      unsigned long off, u##bits val)			\
144  {									\
145  	unsigned long part_offset = (unsigned long)ptr;			\
146  	unsigned long offset = part_offset + off;			\
147  	void *p;							\
148  	int err;							\
149  	char *kaddr;							\
150  	unsigned long map_start;					\
151  	unsigned long map_len;						\
152  	int size = sizeof(u##bits);					\
153  									\
154  	err = map_private_extent_buffer(eb, offset, size,		\
155  			&kaddr, &map_start, &map_len);			\
156  	if (err) {							\
157  		__le##bits val2;					\
158  									\
159  		val2 = cpu_to_le##bits(val);				\
160  		write_extent_buffer(eb, &val2, offset, size);		\
161  		return;							\
162  	}								\
163  	p = kaddr + part_offset - map_start;				\
164  	put_unaligned_le##bits(val, p + off);				\
165  }
166  
167  DEFINE_BTRFS_SETGET_BITS(8)
168  DEFINE_BTRFS_SETGET_BITS(16)
169  DEFINE_BTRFS_SETGET_BITS(32)
170  DEFINE_BTRFS_SETGET_BITS(64)
171  
btrfs_node_key(const struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)172  void btrfs_node_key(const struct extent_buffer *eb,
173  		    struct btrfs_disk_key *disk_key, int nr)
174  {
175  	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
176  	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
177  		       struct btrfs_key_ptr, key, disk_key);
178  }
179