• 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(const struct extent_buffer *eb,		\
54 			       const void *ptr, 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 			    const void *ptr, unsigned long off,		\
94 			    u##bits val,				\
95 			    struct btrfs_map_token *token)		\
96 {									\
97 	unsigned long part_offset = (unsigned long)ptr;			\
98 	unsigned long offset = part_offset + off;			\
99 	void *p;							\
100 	int err;							\
101 	char *kaddr;							\
102 	unsigned long map_start;					\
103 	unsigned long map_len;						\
104 	int size = sizeof(u##bits);					\
105 									\
106 	if (token && token->kaddr && token->offset <= offset &&		\
107 	    token->eb == eb &&						\
108 	   (token->offset + PAGE_CACHE_SIZE >= offset + size)) {	\
109 		kaddr = token->kaddr;					\
110 		p = kaddr + part_offset - token->offset;		\
111 		put_unaligned_le##bits(val, p + off);			\
112 		return;							\
113 	}								\
114 	err = map_private_extent_buffer(eb, offset, size,		\
115 			&kaddr, &map_start, &map_len);			\
116 	if (err) {							\
117 		__le##bits val2;					\
118 									\
119 		val2 = cpu_to_le##bits(val);				\
120 		write_extent_buffer(eb, &val2, offset, size);		\
121 		return;							\
122 	}								\
123 	p = kaddr + part_offset - map_start;				\
124 	put_unaligned_le##bits(val, p + off);				\
125 	if (token) {							\
126 		token->kaddr = kaddr;					\
127 		token->offset = map_start;				\
128 		token->eb = eb;						\
129 	}								\
130 }
131 
132 DEFINE_BTRFS_SETGET_BITS(8)
133 DEFINE_BTRFS_SETGET_BITS(16)
134 DEFINE_BTRFS_SETGET_BITS(32)
135 DEFINE_BTRFS_SETGET_BITS(64)
136 
btrfs_node_key(const struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)137 void btrfs_node_key(const struct extent_buffer *eb,
138 		    struct btrfs_disk_key *disk_key, int nr)
139 {
140 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
141 	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
142 		       struct btrfs_key_ptr, key, disk_key);
143 }
144