diff options
author | Joe Thornber <thornber@redhat.com> | 2011-10-31 16:19:11 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2011-10-31 16:19:11 -0400 |
commit | 3241b1d3e0aaafbfcd320f4d71ade629728cc4f4 (patch) | |
tree | 499461f724d4db3d7118641f4a20f5be23549edd /drivers/md/persistent-data/dm-btree-spine.c | |
parent | 95d402f057f2e208e4631893f6cd4a59c7c05e41 (diff) |
dm: add persistent data library
The persistent-data library offers a re-usable framework for the storage
and management of on-disk metadata in device-mapper targets.
It's used by the thin-provisioning target in the next patch and in an
upcoming hierarchical storage target.
For further information, please read
Documentation/device-mapper/persistent-data.txt
Signed-off-by: Joe Thornber <thornber@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/persistent-data/dm-btree-spine.c')
-rw-r--r-- | drivers/md/persistent-data/dm-btree-spine.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c new file mode 100644 index 000000000000..d9a7912ee8ee --- /dev/null +++ b/drivers/md/persistent-data/dm-btree-spine.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Red Hat, Inc. | ||
3 | * | ||
4 | * This file is released under the GPL. | ||
5 | */ | ||
6 | |||
7 | #include "dm-btree-internal.h" | ||
8 | #include "dm-transaction-manager.h" | ||
9 | |||
10 | #include <linux/device-mapper.h> | ||
11 | |||
12 | #define DM_MSG_PREFIX "btree spine" | ||
13 | |||
14 | /*----------------------------------------------------------------*/ | ||
15 | |||
16 | #define BTREE_CSUM_XOR 121107 | ||
17 | |||
18 | static int node_check(struct dm_block_validator *v, | ||
19 | struct dm_block *b, | ||
20 | size_t block_size); | ||
21 | |||
22 | static void node_prepare_for_write(struct dm_block_validator *v, | ||
23 | struct dm_block *b, | ||
24 | size_t block_size) | ||
25 | { | ||
26 | struct node *n = dm_block_data(b); | ||
27 | struct node_header *h = &n->header; | ||
28 | |||
29 | h->blocknr = cpu_to_le64(dm_block_location(b)); | ||
30 | h->csum = cpu_to_le32(dm_bm_checksum(&h->flags, | ||
31 | block_size - sizeof(__le32), | ||
32 | BTREE_CSUM_XOR)); | ||
33 | |||
34 | BUG_ON(node_check(v, b, 4096)); | ||
35 | } | ||
36 | |||
37 | static int node_check(struct dm_block_validator *v, | ||
38 | struct dm_block *b, | ||
39 | size_t block_size) | ||
40 | { | ||
41 | struct node *n = dm_block_data(b); | ||
42 | struct node_header *h = &n->header; | ||
43 | size_t value_size; | ||
44 | __le32 csum_disk; | ||
45 | uint32_t flags; | ||
46 | |||
47 | if (dm_block_location(b) != le64_to_cpu(h->blocknr)) { | ||
48 | DMERR("node_check failed blocknr %llu wanted %llu", | ||
49 | le64_to_cpu(h->blocknr), dm_block_location(b)); | ||
50 | return -ENOTBLK; | ||
51 | } | ||
52 | |||
53 | csum_disk = cpu_to_le32(dm_bm_checksum(&h->flags, | ||
54 | block_size - sizeof(__le32), | ||
55 | BTREE_CSUM_XOR)); | ||
56 | if (csum_disk != h->csum) { | ||
57 | DMERR("node_check failed csum %u wanted %u", | ||
58 | le32_to_cpu(csum_disk), le32_to_cpu(h->csum)); | ||
59 | return -EILSEQ; | ||
60 | } | ||
61 | |||
62 | value_size = le32_to_cpu(h->value_size); | ||
63 | |||
64 | if (sizeof(struct node_header) + | ||
65 | (sizeof(__le64) + value_size) * le32_to_cpu(h->max_entries) > block_size) { | ||
66 | DMERR("node_check failed: max_entries too large"); | ||
67 | return -EILSEQ; | ||
68 | } | ||
69 | |||
70 | if (le32_to_cpu(h->nr_entries) > le32_to_cpu(h->max_entries)) { | ||
71 | DMERR("node_check failed, too many entries"); | ||
72 | return -EILSEQ; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * The node must be either INTERNAL or LEAF. | ||
77 | */ | ||
78 | flags = le32_to_cpu(h->flags); | ||
79 | if (!(flags & INTERNAL_NODE) && !(flags & LEAF_NODE)) { | ||
80 | DMERR("node_check failed, node is neither INTERNAL or LEAF"); | ||
81 | return -EILSEQ; | ||
82 | } | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | struct dm_block_validator btree_node_validator = { | ||
88 | .name = "btree_node", | ||
89 | .prepare_for_write = node_prepare_for_write, | ||
90 | .check = node_check | ||
91 | }; | ||
92 | |||
93 | /*----------------------------------------------------------------*/ | ||
94 | |||
95 | static int bn_read_lock(struct dm_btree_info *info, dm_block_t b, | ||
96 | struct dm_block **result) | ||
97 | { | ||
98 | return dm_tm_read_lock(info->tm, b, &btree_node_validator, result); | ||
99 | } | ||
100 | |||
101 | static int bn_shadow(struct dm_btree_info *info, dm_block_t orig, | ||
102 | struct dm_btree_value_type *vt, | ||
103 | struct dm_block **result) | ||
104 | { | ||
105 | int r, inc; | ||
106 | |||
107 | r = dm_tm_shadow_block(info->tm, orig, &btree_node_validator, | ||
108 | result, &inc); | ||
109 | if (!r && inc) | ||
110 | inc_children(info->tm, dm_block_data(*result), vt); | ||
111 | |||
112 | return r; | ||
113 | } | ||
114 | |||
115 | int new_block(struct dm_btree_info *info, struct dm_block **result) | ||
116 | { | ||
117 | return dm_tm_new_block(info->tm, &btree_node_validator, result); | ||
118 | } | ||
119 | |||
120 | int unlock_block(struct dm_btree_info *info, struct dm_block *b) | ||
121 | { | ||
122 | return dm_tm_unlock(info->tm, b); | ||
123 | } | ||
124 | |||
125 | /*----------------------------------------------------------------*/ | ||
126 | |||
127 | void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info) | ||
128 | { | ||
129 | s->info = info; | ||
130 | s->count = 0; | ||
131 | s->nodes[0] = NULL; | ||
132 | s->nodes[1] = NULL; | ||
133 | } | ||
134 | |||
135 | int exit_ro_spine(struct ro_spine *s) | ||
136 | { | ||
137 | int r = 0, i; | ||
138 | |||
139 | for (i = 0; i < s->count; i++) { | ||
140 | int r2 = unlock_block(s->info, s->nodes[i]); | ||
141 | if (r2 < 0) | ||
142 | r = r2; | ||
143 | } | ||
144 | |||
145 | return r; | ||
146 | } | ||
147 | |||
148 | int ro_step(struct ro_spine *s, dm_block_t new_child) | ||
149 | { | ||
150 | int r; | ||
151 | |||
152 | if (s->count == 2) { | ||
153 | r = unlock_block(s->info, s->nodes[0]); | ||
154 | if (r < 0) | ||
155 | return r; | ||
156 | s->nodes[0] = s->nodes[1]; | ||
157 | s->count--; | ||
158 | } | ||
159 | |||
160 | r = bn_read_lock(s->info, new_child, s->nodes + s->count); | ||
161 | if (!r) | ||
162 | s->count++; | ||
163 | |||
164 | return r; | ||
165 | } | ||
166 | |||
167 | struct node *ro_node(struct ro_spine *s) | ||
168 | { | ||
169 | struct dm_block *block; | ||
170 | |||
171 | BUG_ON(!s->count); | ||
172 | block = s->nodes[s->count - 1]; | ||
173 | |||
174 | return dm_block_data(block); | ||
175 | } | ||
176 | |||
177 | /*----------------------------------------------------------------*/ | ||
178 | |||
179 | void init_shadow_spine(struct shadow_spine *s, struct dm_btree_info *info) | ||
180 | { | ||
181 | s->info = info; | ||
182 | s->count = 0; | ||
183 | } | ||
184 | |||
185 | int exit_shadow_spine(struct shadow_spine *s) | ||
186 | { | ||
187 | int r = 0, i; | ||
188 | |||
189 | for (i = 0; i < s->count; i++) { | ||
190 | int r2 = unlock_block(s->info, s->nodes[i]); | ||
191 | if (r2 < 0) | ||
192 | r = r2; | ||
193 | } | ||
194 | |||
195 | return r; | ||
196 | } | ||
197 | |||
198 | int shadow_step(struct shadow_spine *s, dm_block_t b, | ||
199 | struct dm_btree_value_type *vt) | ||
200 | { | ||
201 | int r; | ||
202 | |||
203 | if (s->count == 2) { | ||
204 | r = unlock_block(s->info, s->nodes[0]); | ||
205 | if (r < 0) | ||
206 | return r; | ||
207 | s->nodes[0] = s->nodes[1]; | ||
208 | s->count--; | ||
209 | } | ||
210 | |||
211 | r = bn_shadow(s->info, b, vt, s->nodes + s->count); | ||
212 | if (!r) { | ||
213 | if (!s->count) | ||
214 | s->root = dm_block_location(s->nodes[0]); | ||
215 | |||
216 | s->count++; | ||
217 | } | ||
218 | |||
219 | return r; | ||
220 | } | ||
221 | |||
222 | struct dm_block *shadow_current(struct shadow_spine *s) | ||
223 | { | ||
224 | BUG_ON(!s->count); | ||
225 | |||
226 | return s->nodes[s->count - 1]; | ||
227 | } | ||
228 | |||
229 | struct dm_block *shadow_parent(struct shadow_spine *s) | ||
230 | { | ||
231 | BUG_ON(s->count != 2); | ||
232 | |||
233 | return s->count == 2 ? s->nodes[0] : NULL; | ||
234 | } | ||
235 | |||
236 | int shadow_has_parent(struct shadow_spine *s) | ||
237 | { | ||
238 | return s->count >= 2; | ||
239 | } | ||
240 | |||
241 | int shadow_root(struct shadow_spine *s) | ||
242 | { | ||
243 | return s->root; | ||
244 | } | ||