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>
10 #include <linux/export.h>
11 #include <linux/vmalloc.h>
13 #ifdef CONFIG_DM_DEBUG_SPACE_MAPS
15 #define DM_MSG_PREFIX "space map checker"
17 /*----------------------------------------------------------------*/
26 static int ca_get_count(struct count_array
*ca
, dm_block_t b
, uint32_t *count
)
31 *count
= ca
->counts
[b
];
35 static int ca_count_more_than_one(struct count_array
*ca
, dm_block_t b
, int *r
)
40 *r
= ca
->counts
[b
] > 1;
44 static int ca_set_count(struct count_array
*ca
, dm_block_t b
, uint32_t count
)
51 old_count
= ca
->counts
[b
];
53 if (!count
&& old_count
)
56 else if (count
&& !old_count
)
59 ca
->counts
[b
] = count
;
63 static int ca_inc_block(struct count_array
*ca
, dm_block_t b
)
68 ca_set_count(ca
, b
, ca
->counts
[b
] + 1);
72 static int ca_dec_block(struct count_array
*ca
, dm_block_t b
)
77 BUG_ON(ca
->counts
[b
] == 0);
78 ca_set_count(ca
, b
, ca
->counts
[b
] - 1);
82 static int ca_create(struct count_array
*ca
, struct dm_space_map
*sm
)
87 r
= dm_sm_get_nr_blocks(sm
, &nr_blocks
);
92 ca
->nr_free
= nr_blocks
;
97 ca
->counts
= vzalloc(sizeof(*ca
->counts
) * nr_blocks
);
105 static void ca_destroy(struct count_array
*ca
)
110 static int ca_load(struct count_array
*ca
, struct dm_space_map
*sm
)
114 dm_block_t nr_blocks
, i
;
116 r
= dm_sm_get_nr_blocks(sm
, &nr_blocks
);
120 BUG_ON(ca
->nr
!= nr_blocks
);
122 DMWARN("Loading debug space map from disk. This may take some time");
123 for (i
= 0; i
< nr_blocks
; i
++) {
124 r
= dm_sm_get_count(sm
, i
, &count
);
126 DMERR("load failed");
130 ca_set_count(ca
, i
, count
);
132 DMWARN("Load complete");
137 static int ca_extend(struct count_array
*ca
, dm_block_t extra_blocks
)
139 dm_block_t nr_blocks
= ca
->nr
+ extra_blocks
;
140 uint32_t *counts
= vzalloc(sizeof(*counts
) * nr_blocks
);
145 memcpy(counts
, ca
->counts
, sizeof(*counts
) * ca
->nr
);
149 ca
->nr_free
+= extra_blocks
;
154 static int ca_commit(struct count_array
*old
, struct count_array
*new)
156 if (old
->nr
!= new->nr
) {
157 BUG_ON(old
->nr
> new->nr
);
158 ca_extend(old
, new->nr
- old
->nr
);
161 BUG_ON(old
->nr
!= new->nr
);
162 old
->nr_free
= new->nr_free
;
163 memcpy(old
->counts
, new->counts
, sizeof(*old
->counts
) * old
->nr
);
167 /*----------------------------------------------------------------*/
170 struct dm_space_map sm
;
172 struct count_array old_counts
;
173 struct count_array counts
;
175 struct dm_space_map
*real_sm
;
178 static void sm_checker_destroy(struct dm_space_map
*sm
)
180 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
182 dm_sm_destroy(smc
->real_sm
);
183 ca_destroy(&smc
->old_counts
);
184 ca_destroy(&smc
->counts
);
188 static int sm_checker_get_nr_blocks(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_blocks(smc
->real_sm
, count
);
193 BUG_ON(smc
->old_counts
.nr
!= *count
);
197 static int sm_checker_get_nr_free(struct dm_space_map
*sm
, dm_block_t
*count
)
199 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
200 int r
= dm_sm_get_nr_free(smc
->real_sm
, count
);
203 * Slow, but we know it's correct.
206 for (b
= 0; b
< smc
->old_counts
.nr
; b
++)
207 if (smc
->old_counts
.counts
[b
] == 0 &&
208 smc
->counts
.counts
[b
] == 0)
212 DMERR("free block counts differ, checker %u, sm-disk:%u",
213 (unsigned) n
, (unsigned) *count
);
218 static int sm_checker_new_block(struct dm_space_map
*sm
, dm_block_t
*b
)
220 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
221 int r
= dm_sm_new_block(smc
->real_sm
, b
);
224 BUG_ON(*b
>= smc
->old_counts
.nr
);
225 BUG_ON(smc
->old_counts
.counts
[*b
] != 0);
226 BUG_ON(*b
>= smc
->counts
.nr
);
227 BUG_ON(smc
->counts
.counts
[*b
] != 0);
228 ca_set_count(&smc
->counts
, *b
, 1);
234 static int sm_checker_inc_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_inc_block(smc
->real_sm
, b
);
238 int r2
= ca_inc_block(&smc
->counts
, b
);
243 static int sm_checker_dec_block(struct dm_space_map
*sm
, dm_block_t b
)
245 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
246 int r
= dm_sm_dec_block(smc
->real_sm
, b
);
247 int r2
= ca_dec_block(&smc
->counts
, b
);
252 static int sm_checker_get_count(struct dm_space_map
*sm
, dm_block_t b
, uint32_t *result
)
254 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
255 uint32_t result2
= 0;
256 int r
= dm_sm_get_count(smc
->real_sm
, b
, result
);
257 int r2
= ca_get_count(&smc
->counts
, b
, &result2
);
261 BUG_ON(*result
!= result2
);
265 static int sm_checker_count_more_than_one(struct dm_space_map
*sm
, dm_block_t b
, int *result
)
267 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
269 int r
= dm_sm_count_is_more_than_one(smc
->real_sm
, b
, result
);
270 int r2
= ca_count_more_than_one(&smc
->counts
, b
, &result2
);
274 BUG_ON(!(*result
) && result2
);
278 static int sm_checker_set_count(struct dm_space_map
*sm
, dm_block_t b
, uint32_t count
)
280 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
282 int r
= dm_sm_set_count(smc
->real_sm
, b
, count
);
285 BUG_ON(b
>= smc
->counts
.nr
);
286 old_rc
= smc
->counts
.counts
[b
];
287 r2
= ca_set_count(&smc
->counts
, b
, count
);
293 static int sm_checker_commit(struct dm_space_map
*sm
)
295 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
298 r
= dm_sm_commit(smc
->real_sm
);
302 r
= ca_commit(&smc
->old_counts
, &smc
->counts
);
309 static int sm_checker_extend(struct dm_space_map
*sm
, dm_block_t extra_blocks
)
311 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
312 int r
= dm_sm_extend(smc
->real_sm
, extra_blocks
);
316 return ca_extend(&smc
->counts
, extra_blocks
);
319 static int sm_checker_root_size(struct dm_space_map
*sm
, size_t *result
)
321 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
322 return dm_sm_root_size(smc
->real_sm
, result
);
325 static int sm_checker_copy_root(struct dm_space_map
*sm
, void *copy_to_here_le
, size_t len
)
327 struct sm_checker
*smc
= container_of(sm
, struct sm_checker
, sm
);
328 return dm_sm_copy_root(smc
->real_sm
, copy_to_here_le
, len
);
331 /*----------------------------------------------------------------*/
333 static struct dm_space_map ops_
= {
334 .destroy
= sm_checker_destroy
,
335 .get_nr_blocks
= sm_checker_get_nr_blocks
,
336 .get_nr_free
= sm_checker_get_nr_free
,
337 .inc_block
= sm_checker_inc_block
,
338 .dec_block
= sm_checker_dec_block
,
339 .new_block
= sm_checker_new_block
,
340 .get_count
= sm_checker_get_count
,
341 .count_is_more_than_one
= sm_checker_count_more_than_one
,
342 .set_count
= sm_checker_set_count
,
343 .commit
= sm_checker_commit
,
344 .extend
= sm_checker_extend
,
345 .root_size
= sm_checker_root_size
,
346 .copy_root
= sm_checker_copy_root
349 struct dm_space_map
*dm_sm_checker_create(struct dm_space_map
*sm
)
352 struct sm_checker
*smc
;
354 if (IS_ERR_OR_NULL(sm
))
355 return ERR_PTR(-EINVAL
);
357 smc
= kmalloc(sizeof(*smc
), GFP_KERNEL
);
359 return ERR_PTR(-ENOMEM
);
361 memcpy(&smc
->sm
, &ops_
, sizeof(smc
->sm
));
362 r
= ca_create(&smc
->old_counts
, sm
);
368 r
= ca_create(&smc
->counts
, sm
);
370 ca_destroy(&smc
->old_counts
);
377 r
= ca_load(&smc
->counts
, sm
);
379 ca_destroy(&smc
->counts
);
380 ca_destroy(&smc
->old_counts
);
385 r
= ca_commit(&smc
->old_counts
, &smc
->counts
);
387 ca_destroy(&smc
->counts
);
388 ca_destroy(&smc
->old_counts
);
395 EXPORT_SYMBOL_GPL(dm_sm_checker_create
);
397 struct dm_space_map
*dm_sm_checker_create_fresh(struct dm_space_map
*sm
)
400 struct sm_checker
*smc
;
402 if (IS_ERR_OR_NULL(sm
))
403 return ERR_PTR(-EINVAL
);
405 smc
= kmalloc(sizeof(*smc
), GFP_KERNEL
);
407 return ERR_PTR(-ENOMEM
);
409 memcpy(&smc
->sm
, &ops_
, sizeof(smc
->sm
));
410 r
= ca_create(&smc
->old_counts
, sm
);
416 r
= ca_create(&smc
->counts
, sm
);
418 ca_destroy(&smc
->old_counts
);
426 EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh
);
428 /*----------------------------------------------------------------*/
432 struct dm_space_map
*dm_sm_checker_create(struct dm_space_map
*sm
)
436 EXPORT_SYMBOL_GPL(dm_sm_checker_create
);
438 struct dm_space_map
*dm_sm_checker_create_fresh(struct dm_space_map
*sm
)
442 EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh
);
444 /*----------------------------------------------------------------*/