Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.2-rc6 438 lines 9.5 kB view raw
1/* 2 * Copyright (C) 2011 Red Hat, Inc. 3 * 4 * This file is released under the GPL. 5 */ 6 7#include "dm-space-map-checker.h" 8 9#include <linux/device-mapper.h> 10#include <linux/export.h> 11 12#ifdef CONFIG_DM_DEBUG_SPACE_MAPS 13 14#define DM_MSG_PREFIX "space map checker" 15 16/*----------------------------------------------------------------*/ 17 18struct count_array { 19 dm_block_t nr; 20 dm_block_t nr_free; 21 22 uint32_t *counts; 23}; 24 25static int ca_get_count(struct count_array *ca, dm_block_t b, uint32_t *count) 26{ 27 if (b >= ca->nr) 28 return -EINVAL; 29 30 *count = ca->counts[b]; 31 return 0; 32} 33 34static int ca_count_more_than_one(struct count_array *ca, dm_block_t b, int *r) 35{ 36 if (b >= ca->nr) 37 return -EINVAL; 38 39 *r = ca->counts[b] > 1; 40 return 0; 41} 42 43static int ca_set_count(struct count_array *ca, dm_block_t b, uint32_t count) 44{ 45 uint32_t old_count; 46 47 if (b >= ca->nr) 48 return -EINVAL; 49 50 old_count = ca->counts[b]; 51 52 if (!count && old_count) 53 ca->nr_free++; 54 55 else if (count && !old_count) 56 ca->nr_free--; 57 58 ca->counts[b] = count; 59 return 0; 60} 61 62static int ca_inc_block(struct count_array *ca, dm_block_t b) 63{ 64 if (b >= ca->nr) 65 return -EINVAL; 66 67 ca_set_count(ca, b, ca->counts[b] + 1); 68 return 0; 69} 70 71static int ca_dec_block(struct count_array *ca, dm_block_t b) 72{ 73 if (b >= ca->nr) 74 return -EINVAL; 75 76 BUG_ON(ca->counts[b] == 0); 77 ca_set_count(ca, b, ca->counts[b] - 1); 78 return 0; 79} 80 81static int ca_create(struct count_array *ca, struct dm_space_map *sm) 82{ 83 int r; 84 dm_block_t nr_blocks; 85 86 r = dm_sm_get_nr_blocks(sm, &nr_blocks); 87 if (r) 88 return r; 89 90 ca->nr = nr_blocks; 91 ca->nr_free = nr_blocks; 92 ca->counts = kzalloc(sizeof(*ca->counts) * nr_blocks, GFP_KERNEL); 93 if (!ca->counts) 94 return -ENOMEM; 95 96 return 0; 97} 98 99static int ca_load(struct count_array *ca, struct dm_space_map *sm) 100{ 101 int r; 102 uint32_t count; 103 dm_block_t nr_blocks, i; 104 105 r = dm_sm_get_nr_blocks(sm, &nr_blocks); 106 if (r) 107 return r; 108 109 BUG_ON(ca->nr != nr_blocks); 110 111 DMWARN("Loading debug space map from disk. This may take some time"); 112 for (i = 0; i < nr_blocks; i++) { 113 r = dm_sm_get_count(sm, i, &count); 114 if (r) { 115 DMERR("load failed"); 116 return r; 117 } 118 119 ca_set_count(ca, i, count); 120 } 121 DMWARN("Load complete"); 122 123 return 0; 124} 125 126static int ca_extend(struct count_array *ca, dm_block_t extra_blocks) 127{ 128 dm_block_t nr_blocks = ca->nr + extra_blocks; 129 uint32_t *counts = kzalloc(sizeof(*counts) * nr_blocks, GFP_KERNEL); 130 if (!counts) 131 return -ENOMEM; 132 133 memcpy(counts, ca->counts, sizeof(*counts) * ca->nr); 134 kfree(ca->counts); 135 ca->nr = nr_blocks; 136 ca->nr_free += extra_blocks; 137 ca->counts = counts; 138 return 0; 139} 140 141static int ca_commit(struct count_array *old, struct count_array *new) 142{ 143 if (old->nr != new->nr) { 144 BUG_ON(old->nr > new->nr); 145 ca_extend(old, new->nr - old->nr); 146 } 147 148 BUG_ON(old->nr != new->nr); 149 old->nr_free = new->nr_free; 150 memcpy(old->counts, new->counts, sizeof(*old->counts) * old->nr); 151 return 0; 152} 153 154static void ca_destroy(struct count_array *ca) 155{ 156 kfree(ca->counts); 157} 158 159/*----------------------------------------------------------------*/ 160 161struct sm_checker { 162 struct dm_space_map sm; 163 164 struct count_array old_counts; 165 struct count_array counts; 166 167 struct dm_space_map *real_sm; 168}; 169 170static void sm_checker_destroy(struct dm_space_map *sm) 171{ 172 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 173 174 dm_sm_destroy(smc->real_sm); 175 ca_destroy(&smc->old_counts); 176 ca_destroy(&smc->counts); 177 kfree(smc); 178} 179 180static int sm_checker_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count) 181{ 182 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 183 int r = dm_sm_get_nr_blocks(smc->real_sm, count); 184 if (!r) 185 BUG_ON(smc->old_counts.nr != *count); 186 return r; 187} 188 189static int sm_checker_get_nr_free(struct dm_space_map *sm, dm_block_t *count) 190{ 191 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 192 int r = dm_sm_get_nr_free(smc->real_sm, count); 193 if (!r) { 194 /* 195 * Slow, but we know it's correct. 196 */ 197 dm_block_t b, n = 0; 198 for (b = 0; b < smc->old_counts.nr; b++) 199 if (smc->old_counts.counts[b] == 0 && 200 smc->counts.counts[b] == 0) 201 n++; 202 203 if (n != *count) 204 DMERR("free block counts differ, checker %u, sm-disk:%u", 205 (unsigned) n, (unsigned) *count); 206 } 207 return r; 208} 209 210static int sm_checker_new_block(struct dm_space_map *sm, dm_block_t *b) 211{ 212 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 213 int r = dm_sm_new_block(smc->real_sm, b); 214 215 if (!r) { 216 BUG_ON(*b >= smc->old_counts.nr); 217 BUG_ON(smc->old_counts.counts[*b] != 0); 218 BUG_ON(*b >= smc->counts.nr); 219 BUG_ON(smc->counts.counts[*b] != 0); 220 ca_set_count(&smc->counts, *b, 1); 221 } 222 223 return r; 224} 225 226static int sm_checker_inc_block(struct dm_space_map *sm, dm_block_t b) 227{ 228 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 229 int r = dm_sm_inc_block(smc->real_sm, b); 230 int r2 = ca_inc_block(&smc->counts, b); 231 BUG_ON(r != r2); 232 return r; 233} 234 235static int sm_checker_dec_block(struct dm_space_map *sm, dm_block_t b) 236{ 237 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 238 int r = dm_sm_dec_block(smc->real_sm, b); 239 int r2 = ca_dec_block(&smc->counts, b); 240 BUG_ON(r != r2); 241 return r; 242} 243 244static int sm_checker_get_count(struct dm_space_map *sm, dm_block_t b, uint32_t *result) 245{ 246 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 247 uint32_t result2 = 0; 248 int r = dm_sm_get_count(smc->real_sm, b, result); 249 int r2 = ca_get_count(&smc->counts, b, &result2); 250 251 BUG_ON(r != r2); 252 if (!r) 253 BUG_ON(*result != result2); 254 return r; 255} 256 257static int sm_checker_count_more_than_one(struct dm_space_map *sm, dm_block_t b, int *result) 258{ 259 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 260 int result2 = 0; 261 int r = dm_sm_count_is_more_than_one(smc->real_sm, b, result); 262 int r2 = ca_count_more_than_one(&smc->counts, b, &result2); 263 264 BUG_ON(r != r2); 265 if (!r) 266 BUG_ON(!(*result) && result2); 267 return r; 268} 269 270static int sm_checker_set_count(struct dm_space_map *sm, dm_block_t b, uint32_t count) 271{ 272 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 273 uint32_t old_rc; 274 int r = dm_sm_set_count(smc->real_sm, b, count); 275 int r2; 276 277 BUG_ON(b >= smc->counts.nr); 278 old_rc = smc->counts.counts[b]; 279 r2 = ca_set_count(&smc->counts, b, count); 280 BUG_ON(r != r2); 281 282 return r; 283} 284 285static int sm_checker_commit(struct dm_space_map *sm) 286{ 287 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 288 int r; 289 290 r = dm_sm_commit(smc->real_sm); 291 if (r) 292 return r; 293 294 r = ca_commit(&smc->old_counts, &smc->counts); 295 if (r) 296 return r; 297 298 return 0; 299} 300 301static int sm_checker_extend(struct dm_space_map *sm, dm_block_t extra_blocks) 302{ 303 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 304 int r = dm_sm_extend(smc->real_sm, extra_blocks); 305 if (r) 306 return r; 307 308 return ca_extend(&smc->counts, extra_blocks); 309} 310 311static int sm_checker_root_size(struct dm_space_map *sm, size_t *result) 312{ 313 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 314 return dm_sm_root_size(smc->real_sm, result); 315} 316 317static int sm_checker_copy_root(struct dm_space_map *sm, void *copy_to_here_le, size_t len) 318{ 319 struct sm_checker *smc = container_of(sm, struct sm_checker, sm); 320 return dm_sm_copy_root(smc->real_sm, copy_to_here_le, len); 321} 322 323/*----------------------------------------------------------------*/ 324 325static struct dm_space_map ops_ = { 326 .destroy = sm_checker_destroy, 327 .get_nr_blocks = sm_checker_get_nr_blocks, 328 .get_nr_free = sm_checker_get_nr_free, 329 .inc_block = sm_checker_inc_block, 330 .dec_block = sm_checker_dec_block, 331 .new_block = sm_checker_new_block, 332 .get_count = sm_checker_get_count, 333 .count_is_more_than_one = sm_checker_count_more_than_one, 334 .set_count = sm_checker_set_count, 335 .commit = sm_checker_commit, 336 .extend = sm_checker_extend, 337 .root_size = sm_checker_root_size, 338 .copy_root = sm_checker_copy_root 339}; 340 341struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm) 342{ 343 int r; 344 struct sm_checker *smc; 345 346 if (!sm) 347 return NULL; 348 349 smc = kmalloc(sizeof(*smc), GFP_KERNEL); 350 if (!smc) 351 return NULL; 352 353 memcpy(&smc->sm, &ops_, sizeof(smc->sm)); 354 r = ca_create(&smc->old_counts, sm); 355 if (r) { 356 kfree(smc); 357 return NULL; 358 } 359 360 r = ca_create(&smc->counts, sm); 361 if (r) { 362 ca_destroy(&smc->old_counts); 363 kfree(smc); 364 return NULL; 365 } 366 367 smc->real_sm = sm; 368 369 r = ca_load(&smc->counts, sm); 370 if (r) { 371 ca_destroy(&smc->counts); 372 ca_destroy(&smc->old_counts); 373 kfree(smc); 374 return NULL; 375 } 376 377 r = ca_commit(&smc->old_counts, &smc->counts); 378 if (r) { 379 ca_destroy(&smc->counts); 380 ca_destroy(&smc->old_counts); 381 kfree(smc); 382 return NULL; 383 } 384 385 return &smc->sm; 386} 387EXPORT_SYMBOL_GPL(dm_sm_checker_create); 388 389struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm) 390{ 391 int r; 392 struct sm_checker *smc; 393 394 if (!sm) 395 return NULL; 396 397 smc = kmalloc(sizeof(*smc), GFP_KERNEL); 398 if (!smc) 399 return NULL; 400 401 memcpy(&smc->sm, &ops_, sizeof(smc->sm)); 402 r = ca_create(&smc->old_counts, sm); 403 if (r) { 404 kfree(smc); 405 return NULL; 406 } 407 408 r = ca_create(&smc->counts, sm); 409 if (r) { 410 ca_destroy(&smc->old_counts); 411 kfree(smc); 412 return NULL; 413 } 414 415 smc->real_sm = sm; 416 return &smc->sm; 417} 418EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh); 419 420/*----------------------------------------------------------------*/ 421 422#else 423 424struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm) 425{ 426 return sm; 427} 428EXPORT_SYMBOL_GPL(dm_sm_checker_create); 429 430struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm) 431{ 432 return sm; 433} 434EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh); 435 436/*----------------------------------------------------------------*/ 437 438#endif