1 /*
2  * Copyright (C) 2007 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18 
19 #include <linux/highmem.h>
20 
21 /* this is some deeply nasty code.  ctree.h has a different
22  * definition for this BTRFS_SETGET_FUNCS macro, behind a #ifndef
23  *
24  * The end result is that anyone who #includes ctree.h gets a
25  * declaration for the btrfs_set_foo functions and btrfs_foo functions
26  *
27  * This file declares the macros and then #includes ctree.h, which results
28  * in cpp creating the function here based on the template below.
29  *
30  * These setget functions do all the extent_buffer related mapping
31  * required to efficiently read and write specific fields in the extent
32  * buffers.  Every pointer to metadata items in btrfs is really just
33  * an unsigned long offset into the extent buffer which has been
34  * cast to a specific type.  This gives us all the gcc type checking.
35  *
36  * The extent buffer api is used to do all the kmapping and page
37  * spanning work required to get extent buffers in highmem and have
38  * a metadata blocksize different from the page size.
39  *
40  * The macro starts with a simple function prototype declaration so that
41  * sparse won't complain about it being static.
42  */
43 
44 #define BTRFS_SETGET_FUNCS(name, type, member, bits)			\
45 u##bits btrfs_##name(struct extent_buffer *eb, type *s);		\
46 void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val);	\
47 void btrfs_set_token_##name(struct extent_buffer *eb, type *s, u##bits val, struct btrfs_map_token *token);	\
48 u##bits btrfs_token_##name(struct extent_buffer *eb,				\
49 			   type *s, struct btrfs_map_token *token)	\
50 {									\
51 	unsigned long part_offset = (unsigned long)s;			\
52 	unsigned long offset = part_offset + offsetof(type, member);	\
53 	type *p;							\
54 	int err;						\
55 	char *kaddr;						\
56 	unsigned long map_start;				\
57 	unsigned long map_len;					\
58 	unsigned long mem_len = sizeof(((type *)0)->member);	\
59 	u##bits res;						\
60 	if (token && token->kaddr && token->offset <= offset &&	\
61 	    token->eb == eb &&					\
62 	   (token->offset + PAGE_CACHE_SIZE >= offset + mem_len)) { \
63 		kaddr = token->kaddr;				\
64 		p = (type *)(kaddr + part_offset - token->offset);  \
65 		res = le##bits##_to_cpu(p->member);		\
66 		return res;					\
67 	}							\
68 	err = map_private_extent_buffer(eb, offset,		\
69 			mem_len,				\
70 			&kaddr, &map_start, &map_len);		\
71 	if (err) {						\
72 		__le##bits leres;				\
73 		read_eb_member(eb, s, type, member, &leres);	\
74 		return le##bits##_to_cpu(leres);		\
75 	}							\
76 	p = (type *)(kaddr + part_offset - map_start);		\
77 	res = le##bits##_to_cpu(p->member);			\
78 	if (token) {						\
79 		token->kaddr = kaddr;				\
80 		token->offset = map_start;			\
81 		token->eb = eb;					\
82 	}							\
83 	return res;						\
84 }									\
85 void btrfs_set_token_##name(struct extent_buffer *eb,				\
86 			    type *s, u##bits val, struct btrfs_map_token *token)		\
87 {									\
88 	unsigned long part_offset = (unsigned long)s;			\
89 	unsigned long offset = part_offset + offsetof(type, member);	\
90 	type *p;							\
91 	int err;						\
92 	char *kaddr;						\
93 	unsigned long map_start;				\
94 	unsigned long map_len;					\
95 	unsigned long mem_len = sizeof(((type *)0)->member);	\
96 	if (token && token->kaddr && token->offset <= offset &&	\
97 	    token->eb == eb &&					\
98 	   (token->offset + PAGE_CACHE_SIZE >= offset + mem_len)) { \
99 		kaddr = token->kaddr;				\
100 		p = (type *)(kaddr + part_offset - token->offset);  \
101 		p->member = cpu_to_le##bits(val);		\
102 		return;						\
103 	}							\
104 	err = map_private_extent_buffer(eb, offset,		\
105 			mem_len,				\
106 			&kaddr, &map_start, &map_len);		\
107 	if (err) {						\
108 		__le##bits val2;				\
109 		val2 = cpu_to_le##bits(val);			\
110 		write_eb_member(eb, s, type, member, &val2);	\
111 		return;						\
112 	}							\
113 	p = (type *)(kaddr + part_offset - map_start);		\
114 	p->member = cpu_to_le##bits(val);			\
115 	if (token) {						\
116 		token->kaddr = kaddr;				\
117 		token->offset = map_start;			\
118 		token->eb = eb;					\
119 	}							\
120 }								\
121 void btrfs_set_##name(struct extent_buffer *eb,			\
122 		      type *s, u##bits val)			\
123 {								\
124 	btrfs_set_token_##name(eb, s, val, NULL);		\
125 }								\
126 u##bits btrfs_##name(struct extent_buffer *eb,			\
127 		      type *s)					\
128 {								\
129 	return btrfs_token_##name(eb, s, NULL);			\
130 }								\
131 
132 #include "ctree.h"
133 
btrfs_node_key(struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)134 void btrfs_node_key(struct extent_buffer *eb,
135 		    struct btrfs_disk_key *disk_key, int nr)
136 {
137 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
138 	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
139 		       struct btrfs_key_ptr, key, disk_key);
140 }
141