• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 u##bits btrfs_##name(struct extent_buffer *eb,				\
48 				   type *s)				\
49 {									\
50 	unsigned long part_offset = (unsigned long)s;			\
51 	unsigned long offset = part_offset + offsetof(type, member);	\
52 	type *p;							\
53 	/* ugly, but we want the fast path here */			\
54 	if (eb->map_token && offset >= eb->map_start &&			\
55 	    offset + sizeof(((type *)0)->member) <= eb->map_start +	\
56 	    eb->map_len) {						\
57 		p = (type *)(eb->kaddr + part_offset - eb->map_start);	\
58 		return le##bits##_to_cpu(p->member);			\
59 	}								\
60 	{								\
61 		int err;						\
62 		char *map_token;					\
63 		char *kaddr;						\
64 		int unmap_on_exit = (eb->map_token == NULL);		\
65 		unsigned long map_start;				\
66 		unsigned long map_len;					\
67 		u##bits res;						\
68 		err = map_extent_buffer(eb, offset,			\
69 				sizeof(((type *)0)->member),		\
70 				&map_token, &kaddr,			\
71 				&map_start, &map_len, KM_USER1);	\
72 		if (err) {						\
73 			__le##bits leres;				\
74 			read_eb_member(eb, s, type, member, &leres);	\
75 			return le##bits##_to_cpu(leres);		\
76 		}							\
77 		p = (type *)(kaddr + part_offset - map_start);		\
78 		res = le##bits##_to_cpu(p->member);			\
79 		if (unmap_on_exit)					\
80 			unmap_extent_buffer(eb, map_token, KM_USER1);	\
81 		return res;						\
82 	}								\
83 }									\
84 void btrfs_set_##name(struct extent_buffer *eb,				\
85 				    type *s, u##bits val)		\
86 {									\
87 	unsigned long part_offset = (unsigned long)s;			\
88 	unsigned long offset = part_offset + offsetof(type, member);	\
89 	type *p;							\
90 	/* ugly, but we want the fast path here */			\
91 	if (eb->map_token && offset >= eb->map_start &&			\
92 	    offset + sizeof(((type *)0)->member) <= eb->map_start +	\
93 	    eb->map_len) {						\
94 		p = (type *)(eb->kaddr + part_offset - eb->map_start);	\
95 		p->member = cpu_to_le##bits(val);			\
96 		return;							\
97 	}								\
98 	{								\
99 		int err;						\
100 		char *map_token;					\
101 		char *kaddr;						\
102 		int unmap_on_exit = (eb->map_token == NULL);		\
103 		unsigned long map_start;				\
104 		unsigned long map_len;					\
105 		err = map_extent_buffer(eb, offset,			\
106 				sizeof(((type *)0)->member),		\
107 				&map_token, &kaddr,			\
108 				&map_start, &map_len, KM_USER1);	\
109 		if (err) {						\
110 			__le##bits val2;				\
111 			val2 = cpu_to_le##bits(val);			\
112 			write_eb_member(eb, s, type, member, &val2);	\
113 			return;						\
114 		}							\
115 		p = (type *)(kaddr + part_offset - map_start);		\
116 		p->member = cpu_to_le##bits(val);			\
117 		if (unmap_on_exit)					\
118 			unmap_extent_buffer(eb, map_token, KM_USER1);	\
119 	}								\
120 }
121 
122 #include "ctree.h"
123 
btrfs_node_key(struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)124 void btrfs_node_key(struct extent_buffer *eb,
125 		    struct btrfs_disk_key *disk_key, int nr)
126 {
127 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
128 	if (eb->map_token && ptr >= eb->map_start &&
129 	    ptr + sizeof(*disk_key) <= eb->map_start + eb->map_len) {
130 		memcpy(disk_key, eb->kaddr + ptr - eb->map_start,
131 			sizeof(*disk_key));
132 		return;
133 	} else if (eb->map_token) {
134 		unmap_extent_buffer(eb, eb->map_token, KM_USER1);
135 		eb->map_token = NULL;
136 	}
137 	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
138 		       struct btrfs_key_ptr, key, disk_key);
139 }
140