dm-space-map-checker.c 9.5 KB

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