Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
struct-funcs.c
Go to the documentation of this file.
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 
24 static inline u8 get_unaligned_le8(const void *p)
25 {
26  return *(u8 *)p;
27 }
28 
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 
135 
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 }