dm-space-map-checker.c 9.3 KB

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