• 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 #include <asm/unaligned.h>
21 
22 #include "ctree.h"
23 
get_unaligned_le8(const void * p)24 static inline u8 get_unaligned_le8(const void *p)
25 {
26        return *(u8 *)p;
27 }
28 
put_unaligned_le8(u8 val,void * p)29 static inline void put_unaligned_le8(u8 val, void *p)
30 {
31        *(u8 *)p = val;
32 }
33 
34 /*
35  * this is some deeply nasty code.
36  *
37  * The end result is that anyone who #includes ctree.h gets a
38  * declaration for the btrfs_set_foo functions and btrfs_foo functions,
39  * which are wappers of btrfs_set_token_#bits functions and
40  * btrfs_get_token_#bits functions, which are defined in this file.
41  *
42  * These setget functions do all the extent_buffer related mapping
43  * required to efficiently read and write specific fields in the extent
44  * buffers.  Every pointer to metadata items in btrfs is really just
45  * an unsigned long offset into the extent buffer which has been
46  * cast to a specific type.  This gives us all the gcc type checking.
47  *
48  * The extent buffer api is used to do the page spanning work required to
49  * have a metadata blocksize different from the page size.
50  */
51 
52 #define DEFINE_BTRFS_SETGET_BITS(bits)					\
53 u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr,	\
54 			       unsigned long off,			\
55 			       struct btrfs_map_token *token)		\
56 {									\
57 	unsigned long part_offset = (unsigned long)ptr;			\
58 	unsigned long offset = part_offset + off;			\
59 	void *p;							\
60 	int err;							\
61 	char *kaddr;							\
62 	unsigned long map_start;					\
63 	unsigned long map_len;						\
64 	int size = sizeof(u##bits);					\
65 	u##bits res;							\
66 									\
67 	if (token && token->kaddr && token->offset <= offset &&		\
68 	    token->eb == eb &&						\
69 	   (token->offset + PAGE_CACHE_SIZE >= offset + size)) {	\
70 		kaddr = token->kaddr;					\
71 		p = kaddr + part_offset - token->offset;		\
72 		res = get_unaligned_le##bits(p + off);			\
73 		return res;						\
74 	}								\
75 	err = map_private_extent_buffer(eb, offset, size,		\
76 					&kaddr, &map_start, &map_len);	\
77 	if (err) {							\
78 		__le##bits leres;					\
79 									\
80 		read_extent_buffer(eb, &leres, offset, size);		\
81 		return le##bits##_to_cpu(leres);			\
82 	}								\
83 	p = kaddr + part_offset - map_start;				\
84 	res = get_unaligned_le##bits(p + off);				\
85 	if (token) {							\
86 		token->kaddr = kaddr;					\
87 		token->offset = map_start;				\
88 		token->eb = eb;						\
89 	}								\
90 	return res;							\
91 }									\
92 void btrfs_set_token_##bits(struct extent_buffer *eb,			\
93 			    void *ptr, unsigned long off, u##bits val,	\
94 			    struct btrfs_map_token *token)		\
95 {									\
96 	unsigned long part_offset = (unsigned long)ptr;			\
97 	unsigned long offset = part_offset + off;			\
98 	void *p;							\
99 	int err;							\
100 	char *kaddr;							\
101 	unsigned long map_start;					\
102 	unsigned long map_len;						\
103 	int size = sizeof(u##bits);					\
104 									\
105 	if (token && token->kaddr && token->offset <= offset &&		\
106 	    token->eb == eb &&						\
107 	   (token->offset + PAGE_CACHE_SIZE >= offset + size)) {	\
108 		kaddr = token->kaddr;					\
109 		p = kaddr + part_offset - token->offset;		\
110 		put_unaligned_le##bits(val, p + off);			\
111 		return;							\
112 	}								\
113 	err = map_private_extent_buffer(eb, offset, size,		\
114 			&kaddr, &map_start, &map_len);			\
115 	if (err) {							\
116 		__le##bits val2;					\
117 									\
118 		val2 = cpu_to_le##bits(val);				\
119 		write_extent_buffer(eb, &val2, offset, size);		\
120 		return;							\
121 	}								\
122 	p = kaddr + part_offset - map_start;				\
123 	put_unaligned_le##bits(val, p + off);				\
124 	if (token) {							\
125 		token->kaddr = kaddr;					\
126 		token->offset = map_start;				\
127 		token->eb = eb;						\
128 	}								\
129 }
130 
131 DEFINE_BTRFS_SETGET_BITS(8)
132 DEFINE_BTRFS_SETGET_BITS(16)
133 DEFINE_BTRFS_SETGET_BITS(32)
134 DEFINE_BTRFS_SETGET_BITS(64)
135 
btrfs_node_key(struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)136 void btrfs_node_key(struct extent_buffer *eb,
137 		    struct btrfs_disk_key *disk_key, int nr)
138 {
139 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
140 	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
141 		       struct btrfs_key_ptr, key, disk_key);
142 }
143