2 * Copyright (C) 2011 Red Hat, Inc.
4 * This file is released under the GPL.
7 #include "dm-space-map-checker.h"
9 #include <linux/device-mapper.h>
11 #ifdef CONFIG_DM_DEBUG_SPACE_MAPS
13 #define DM_MSG_PREFIX "space map checker"
15 /*----------------------------------------------------------------*/
24 static int ca_get_count(struct count_array
*ca
, dm_block_t b
, uint32_t *count
)
29 *count
= ca
->counts
[b
];
33 static int ca_count_more_than_one(struct count_array
*ca
, dm_block_t b
, int *r
)
38 *r
= ca
->counts
[b
] > 1;
42 static int ca_set_count(struct count_array
*ca
, dm_block_t b
, uint32_t count
)
49 old_count
= ca
->counts
[b
];
51 if (!count
&& old_count
)
54 else if (count
&& !old_count
)
57 ca
->counts
[b
] = count
;
61 static int ca_inc_block(struct count_array
*ca
, dm_block_t b
)
66 ca_set_count(ca
, b
, ca
->counts
[b
] + 1);
70 static int ca_dec_block(struct count_array
*ca
, dm_block_t b
)
75 BUG_ON(ca
->counts
[b
] == 0);
76 ca_set_count(ca
, b
, ca
->counts
[b
] - 1);
80 static int ca_create(struct count_array
*ca
, struct dm_space_map
*sm
)
85 r
= dm_sm_get_nr_blocks(sm
, &nr_blocks
);
90 ca
->nr_free
= nr_blocks
;
91 ca
->counts
= kzalloc(sizeof(*ca
->counts
) * nr_blocks
, GFP_KERNEL
);
98 static int ca_load(struct count_array
*ca
, struct dm_space_map
*sm
)
102 dm_block_t nr_blocks
, i
;
104 r
= dm_sm_get_nr_blocks(sm
, &nr_blocks
);
108 BUG_ON(ca
->nr
!= nr_blocks
);
110 DMWARN("Loading debug space map from disk. This may take some time");
111 for (i
= 0; i
< nr_blocks
; i
++) {
112 r
= dm_sm_get_count(sm
, i
, &count
);
114 DMERR("load failed");
118 ca_set_count(ca
, i
, count
);
120 DMWARN("Load complete");
125 static int ca_extend(struct count_array
*ca
, dm_block_t extra_blocks
)
127 dm_block_t nr_blocks
= ca
->nr
+ extra_blocks
;
128 uint32_t *counts
= kzalloc(sizeof(*counts
) * nr_blocks
, GFP_KERNEL
);
132 memcpy(counts
, ca
->counts
, sizeof(*counts
) * ca
->nr
);
135 ca
->nr_free
+= extra_blocks
;
140 static int ca_commit(struct count_array
*old
, struct count_array
*new)
142 if (old
->nr
!= new->nr
) {
143 BUG_ON(old
->nr
> new->nr
);
144 ca_extend(old
, new->nr
- old
->nr
);
147 BUG_ON(old
->nr
!= new->nr
);
148 old
->nr_free
= new->nr_free
;
149 memcpy(old
->counts
, new->counts
, sizeof(*old
->counts
) * old
->nr
);
153 static void ca_destroy(struct count_array
*ca
)
158 /*----------------------------------------------------------------*/
161 struct dm_space_map sm
;
163 struct count_array old_counts
;
164 struct count_array counts
;
166 struct dm_space_map
*real_sm
;
169 static void sm_checker_destroy(struct dm_space_map
*sm
)
171 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
173 dm_sm_destroy(smc
->real_sm
);
174 ca_destroy(&smc
->old_counts
);
175 ca_destroy(&smc
->counts
);
179 static int sm_checker_get_nr_blocks(struct dm_space_map
*sm
, dm_block_t
*count
)
181 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
182 int r
= dm_sm_get_nr_blocks(smc
->real_sm
, count
);
184 BUG_ON(smc
->old_counts
.nr
!= *count
);
188 static int sm_checker_get_nr_free(struct dm_space_map
*sm
, dm_block_t
*count
)
190 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
191 int r
= dm_sm_get_nr_free(smc
->real_sm
, count
);
194 * Slow, but we know it's correct.
197 for (b
= 0; b
< smc
->old_counts
.nr
; b
++)
198 if (smc
->old_counts
.counts
[b
] == 0 &&
199 smc
->counts
.counts
[b
] == 0)
203 DMERR("free block counts differ, checker %u, sm-disk:%u",
204 (unsigned) n
, (unsigned) *count
);
209 static int sm_checker_new_block(struct dm_space_map
*sm
, dm_block_t
*b
)
211 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
212 int r
= dm_sm_new_block(smc
->real_sm
, b
);
215 BUG_ON(*b
>= smc
->old_counts
.nr
);
216 BUG_ON(smc
->old_counts
.counts
[*b
] != 0);
217 BUG_ON(*b
>= smc
->counts
.nr
);
218 BUG_ON(smc
->counts
.counts
[*b
] != 0);
219 ca_set_count(&smc
->counts
, *b
, 1);
225 static int sm_checker_inc_block(struct dm_space_map
*sm
, dm_block_t b
)
227 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
228 int r
= dm_sm_inc_block(smc
->real_sm
, b
);
229 int r2
= ca_inc_block(&smc
->counts
, b
);
234 static int sm_checker_dec_block(struct dm_space_map
*sm
, dm_block_t b
)
236 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
237 int r
= dm_sm_dec_block(smc
->real_sm
, b
);
238 int r2
= ca_dec_block(&smc
->counts
, b
);
243 static int sm_checker_get_count(struct dm_space_map
*sm
, dm_block_t b
, uint32_t *result
)
245 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
246 uint32_t result2
= 0;
247 int r
= dm_sm_get_count(smc
->real_sm
, b
, result
);
248 int r2
= ca_get_count(&smc
->counts
, b
, &result2
);
252 BUG_ON(*result
!= result2
);
256 static int sm_checker_count_more_than_one(struct dm_space_map
*sm
, dm_block_t b
, int *result
)
258 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
260 int r
= dm_sm_count_is_more_than_one(smc
->real_sm
, b
, result
);
261 int r2
= ca_count_more_than_one(&smc
->counts
, b
, &result2
);
265 BUG_ON(!(*result
) && result2
);
269 static int sm_checker_set_count(struct dm_space_map
*sm
, dm_block_t b
, uint32_t count
)
271 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
273 int r
= dm_sm_set_count(smc
->real_sm
, b
, count
);
276 BUG_ON(b
>= smc
->counts
.nr
);
277 old_rc
= smc
->counts
.counts
[b
];
278 r2
= ca_set_count(&smc
->counts
, b
, count
);
284 static int sm_checker_commit(struct dm_space_map
*sm
)
286 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
289 r
= dm_sm_commit(smc
->real_sm
);
293 r
= ca_commit(&smc
->old_counts
, &smc
->counts
);
300 static int sm_checker_extend(struct dm_space_map
*sm
, dm_block_t extra_blocks
)
302 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
303 int r
= dm_sm_extend(smc
->real_sm
, extra_blocks
);
307 return ca_extend(&smc
->counts
, extra_blocks
);
310 static int sm_checker_root_size(struct dm_space_map
*sm
, size_t *result
)
312 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
313 return dm_sm_root_size(smc
->real_sm
, result
);
316 static int sm_checker_copy_root(struct dm_space_map
*sm
, void *copy_to_here_le
, size_t len
)
318 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
319 return dm_sm_copy_root(smc
->real_sm
, copy_to_here_le
, len
);
322 /*----------------------------------------------------------------*/
324 static struct dm_space_map ops_
= {
325 .destroy
= sm_checker_destroy
,
326 .get_nr_blocks
= sm_checker_get_nr_blocks
,
327 .get_nr_free
= sm_checker_get_nr_free
,
328 .inc_block
= sm_checker_inc_block
,
329 .dec_block
= sm_checker_dec_block
,
330 .new_block
= sm_checker_new_block
,
331 .get_count
= sm_checker_get_count
,
332 .count_is_more_than_one
= sm_checker_count_more_than_one
,
333 .set_count
= sm_checker_set_count
,
334 .commit
= sm_checker_commit
,
335 .extend
= sm_checker_extend
,
336 .root_size
= sm_checker_root_size
,
337 .copy_root
= sm_checker_copy_root
340 struct dm_space_map
*dm_sm_checker_create(struct dm_space_map
*sm
)
343 struct sm_checker
*smc
;
348 smc
= kmalloc(sizeof(*smc
), GFP_KERNEL
);
352 memcpy(&smc
->sm
, &ops_
, sizeof(smc
->sm
));
353 r
= ca_create(&smc
->old_counts
, sm
);
359 r
= ca_create(&smc
->counts
, sm
);
361 ca_destroy(&smc
->old_counts
);
368 r
= ca_load(&smc
->counts
, sm
);
370 ca_destroy(&smc
->counts
);
371 ca_destroy(&smc
->old_counts
);
376 r
= ca_commit(&smc
->old_counts
, &smc
->counts
);
378 ca_destroy(&smc
->counts
);
379 ca_destroy(&smc
->old_counts
);
386 EXPORT_SYMBOL_GPL(dm_sm_checker_create
);
388 struct dm_space_map
*dm_sm_checker_create_fresh(struct dm_space_map
*sm
)
391 struct sm_checker
*smc
;
396 smc
= kmalloc(sizeof(*smc
), GFP_KERNEL
);
400 memcpy(&smc
->sm
, &ops_
, sizeof(smc
->sm
));
401 r
= ca_create(&smc
->old_counts
, sm
);
407 r
= ca_create(&smc
->counts
, sm
);
409 ca_destroy(&smc
->old_counts
);
417 EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh
);
419 /*----------------------------------------------------------------*/
423 struct dm_space_map
*dm_sm_checker_create(struct dm_space_map
*sm
)
427 EXPORT_SYMBOL_GPL(dm_sm_checker_create
);
429 struct dm_space_map
*dm_sm_checker_create_fresh(struct dm_space_map
*sm
)
433 EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh
);
435 /*----------------------------------------------------------------*/