OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 The Chromium OS Authors <chromium-os-dev@chromium.org> | 2 * Copyright (C) 2010 The Chromium OS Authors <chromium-os-dev@chromium.org> |
3 * | 3 * |
4 * Device-Mapper block hash tree interface. | 4 * Device-Mapper block hash tree interface. |
5 * See Documentation/device-mapper/dm-bht.txt for details. | 5 * See Documentation/device-mapper/dm-bht.txt for details. |
6 * | 6 * |
7 * This file is released under the GPL. | 7 * This file is released under the GPL. |
8 */ | 8 */ |
9 | 9 |
10 #include <asm/atomic.h> | 10 #include <asm/atomic.h> |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 } | 307 } |
308 | 308 |
309 /* Setup callback stubs */ | 309 /* Setup callback stubs */ |
310 bht->read_cb = &dm_bht_read_callback_stub; | 310 bht->read_cb = &dm_bht_read_callback_stub; |
311 bht->write_cb = &dm_bht_write_callback_stub; | 311 bht->write_cb = &dm_bht_write_callback_stub; |
312 | 312 |
313 status = dm_bht_initialize_entries(bht); | 313 status = dm_bht_initialize_entries(bht); |
314 if (status) | 314 if (status) |
315 goto bad_entries_alloc; | 315 goto bad_entries_alloc; |
316 | 316 |
| 317 /* We compute depth such that there is only be 1 block at level 0. */ |
| 318 BUG_ON(bht->levels[0].count != 1); |
| 319 |
317 return 0; | 320 return 0; |
318 | 321 |
319 bad_entries_alloc: | 322 bad_entries_alloc: |
320 while (bht->depth-- > 0) | 323 while (bht->depth-- > 0) |
321 kfree(bht->levels[bht->depth].entries); | 324 kfree(bht->levels[bht->depth].entries); |
322 kfree(bht->levels); | 325 kfree(bht->levels); |
323 bad_node_count: | 326 bad_node_count: |
324 bad_level_alloc: | 327 bad_level_alloc: |
325 bad_block_count: | 328 bad_block_count: |
326 kfree(bht->root_digest); | 329 kfree(bht->root_digest); |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 { | 466 { |
464 if (status) { | 467 if (status) { |
465 DMCRIT("an I/O error occurred while writing entry"); | 468 DMCRIT("an I/O error occurred while writing entry"); |
466 atomic_set(&entry->state, DM_BHT_ENTRY_ERROR_IO); | 469 atomic_set(&entry->state, DM_BHT_ENTRY_ERROR_IO); |
467 /* entry->nodes will be freed later */ | 470 /* entry->nodes will be freed later */ |
468 return; | 471 return; |
469 } | 472 } |
470 } | 473 } |
471 EXPORT_SYMBOL(dm_bht_write_completed); | 474 EXPORT_SYMBOL(dm_bht_write_completed); |
472 | 475 |
| 476 /* dm_bht_maybe_read_entry |
| 477 * Attempts to atomically acquire an entry, allocate any needed |
| 478 * memory, and issues the I/O callback to load the hash from disk. |
| 479 * Return value is negative on error. When positive, it is the state |
| 480 * value. |
| 481 */ |
| 482 static int dm_bht_maybe_read_entry(struct dm_bht *bht, void *ctx, |
| 483 unsigned int depth, unsigned int index) |
| 484 { |
| 485 struct dm_bht_level *level = &bht->levels[depth]; |
| 486 struct dm_bht_entry *entry = &level->entries[index]; |
| 487 sector_t current_sector = level->sector + to_sector(index * PAGE_SIZE); |
| 488 struct page *node_page; |
| 489 int state; |
473 | 490 |
474 /* dm_bht_maybe_read_entries | |
475 * Attempts to atomically acquire each entry, allocated any needed | |
476 * memory, and issues I/O callbacks to load the hashes from disk. | |
477 * Returns 0 if all entries are loaded and verified. On error, the | |
478 * return value is negative. When positive, it is the state values | |
479 * ORd. | |
480 */ | |
481 static int dm_bht_maybe_read_entries(struct dm_bht *bht, void *ctx, | |
482 unsigned int depth, unsigned int index, | |
483 unsigned int count, bool until_exist) | |
484 { | |
485 struct dm_bht_level *level; | |
486 struct dm_bht_entry *entry, *last_entry; | |
487 sector_t current_sector; | |
488 int state = 0; | |
489 int status = 0; | |
490 struct page *node_page = NULL; | |
491 BUG_ON(depth >= bht->depth); | 491 BUG_ON(depth >= bht->depth); |
492 | 492 |
493 level = &bht->levels[depth]; | |
494 if (count > level->count - index) { | |
495 DMERR("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " | |
496 "index+count exceeds available entries %u", | |
497 depth, index, count, level->count); | |
498 return -EINVAL; | |
499 } | |
500 /* XXX: hardcoding PAGE_SIZE means that a perfectly valid image | 493 /* XXX: hardcoding PAGE_SIZE means that a perfectly valid image |
501 * on one system may not work on a different kernel. | 494 * on one system may not work on a different kernel. |
502 * TODO(wad) abstract PAGE_SIZE with a bht->entry_size or | 495 * TODO(wad) abstract PAGE_SIZE with a bht->entry_size or |
503 * at least a define and ensure bht->entry_size is | 496 * at least a define and ensure bht->entry_size is |
504 * sector aligned at least. | 497 * sector aligned at least. |
505 */ | 498 */ |
506 current_sector = level->sector + to_sector(index * PAGE_SIZE); | |
507 for (entry = &level->entries[index], last_entry = entry + count; | |
508 entry < last_entry; | |
509 ++entry, current_sector += to_sector(PAGE_SIZE)) { | |
510 /* If the entry's state is UNALLOCATED, then we'll claim it | |
511 * for allocation and loading. | |
512 */ | |
513 state = atomic_cmpxchg(&entry->state, | |
514 DM_BHT_ENTRY_UNALLOCATED, | |
515 DM_BHT_ENTRY_PENDING); | |
516 DMDEBUG("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " | |
517 "ei=%lu, state=%d", | |
518 depth, index, count, | |
519 (unsigned long)(entry - level->entries), state); | |
520 if (state <= DM_BHT_ENTRY_ERROR) { | |
521 DMCRIT("entry %u is in an error state", index); | |
522 return state; | |
523 } | |
524 | 499 |
525 » » /* Currently, the verified state is unused. */ | 500 » /* If the entry's state is UNALLOCATED, then we'll claim it |
526 » » if (state == DM_BHT_ENTRY_VERIFIED) { | 501 » * for allocation and loading. |
527 » » » if (until_exist) | 502 » */ |
528 » » » » return 0; | 503 » state = atomic_cmpxchg(&entry->state, |
529 » » » /* Makes 0 == verified. Is that ideal? */ | 504 » » » DM_BHT_ENTRY_UNALLOCATED, |
530 » » » continue; | 505 » » » DM_BHT_ENTRY_PENDING); |
531 » » } | 506 » DMDEBUG("dm_bht_maybe_read_entry(d=%u,ei=%u): ei=%lu, state=%d", |
| 507 » » depth, index, (unsigned long)(entry - level->entries), state); |
532 | 508 |
533 » » if (state != DM_BHT_ENTRY_UNALLOCATED) { | 509 » if (state != DM_BHT_ENTRY_UNALLOCATED) |
534 » » » /* PENDING, READY, ... */ | 510 » » goto out; |
535 » » » if (until_exist) | |
536 » » » » return state; | |
537 » » » status |= state; | |
538 » » » continue; | |
539 » » } | |
540 » » /* Current entry is claimed for allocation and loading */ | |
541 » » node_page = (struct page *) mempool_alloc(bht->entry_pool, | |
542 » » » » » » » GFP_NOIO); | |
543 » » if (!node_page) { | |
544 » » » DMCRIT("failed to allocate memory for " | |
545 » » » "entry->nodes from pool"); | |
546 » » » return -ENOMEM; | |
547 » » } | |
548 » » /* dm-bht guarantees page-aligned memory for callbacks. */ | |
549 » » entry->nodes = page_address(node_page); | |
550 » » /* Let the caller know that not all the data is yet available */ | |
551 » » status |= DM_BHT_ENTRY_REQUESTED; | |
552 » » /* Issue the read callback */ | |
553 » » /* TODO(wad) error check callback here too */ | |
554 » » DMDEBUG("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " | |
555 » » » "reading %lu", | |
556 » » » depth, index, count, | |
557 » » » (unsigned long)(entry - level->entries)); | |
558 » » bht->read_cb(ctx, /* external context */ | |
559 » » » current_sector, /* starting sector */ | |
560 » » » entry->nodes, /* destination */ | |
561 » » » to_sector(PAGE_SIZE), | |
562 » » » entry); /* io context */ | |
563 | 511 |
564 » } | 512 » state = DM_BHT_ENTRY_REQUESTED; |
565 » /* Should only be 0 if all entries were verified and not just ready */ | 513 |
566 » return status; | 514 » /* Current entry is claimed for allocation and loading */ |
| 515 » node_page = (struct page *) mempool_alloc(bht->entry_pool, GFP_NOIO); |
| 516 » if (!node_page) |
| 517 » » goto nomem; |
| 518 » /* dm-bht guarantees page-aligned memory for callbacks. */ |
| 519 » entry->nodes = page_address(node_page); |
| 520 |
| 521 » /* TODO(wad) error check callback here too */ |
| 522 » DMDEBUG("dm_bht_maybe_read_entry(d=%u,ei=%u): reading %lu", |
| 523 » » depth, index, (unsigned long)(entry - level->entries)); |
| 524 » bht->read_cb(ctx, current_sector, entry->nodes, |
| 525 » » to_sector(PAGE_SIZE), entry); |
| 526 |
| 527 out: |
| 528 » if (state <= DM_BHT_ENTRY_ERROR) |
| 529 » » DMCRIT("entry %u is in an error state", index); |
| 530 |
| 531 » return state; |
| 532 |
| 533 nomem: |
| 534 » DMCRIT("failed to allocate memory for entry->nodes from pool"); |
| 535 » return -ENOMEM; |
| 536 |
| 537 |
567 } | 538 } |
568 | 539 |
569 static int dm_bht_compare_hash(struct dm_bht *bht, u8 *known, u8 *computed) | 540 static int dm_bht_compare_hash(struct dm_bht *bht, u8 *known, u8 *computed) |
570 { | 541 { |
571 return memcmp(known, computed, bht->digest_size); | 542 return memcmp(known, computed, bht->digest_size); |
572 } | 543 } |
573 | 544 |
574 static int dm_bht_update_hash(struct dm_bht *bht, u8 *known, u8 *computed) | 545 static int dm_bht_update_hash(struct dm_bht *bht, u8 *known, u8 *computed) |
575 { | 546 { |
576 #ifdef CONFIG_DM_DEBUG | 547 #ifdef CONFIG_DM_DEBUG |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
825 { | 796 { |
826 int depth, r; | 797 int depth, r; |
827 | 798 |
828 for (depth = bht->depth - 2; depth >= 0; depth--) { | 799 for (depth = bht->depth - 2; depth >= 0; depth--) { |
829 struct dm_bht_level *level = dm_bht_get_level(bht, depth); | 800 struct dm_bht_level *level = dm_bht_get_level(bht, depth); |
830 struct dm_bht_level *child_level = level + 1; | 801 struct dm_bht_level *child_level = level + 1; |
831 struct dm_bht_entry *entry = level->entries; | 802 struct dm_bht_entry *entry = level->entries; |
832 struct dm_bht_entry *child = child_level->entries; | 803 struct dm_bht_entry *child = child_level->entries; |
833 unsigned int i, j; | 804 unsigned int i, j; |
834 | 805 |
835 r = dm_bht_maybe_read_entries(bht, read_cb_ctx, depth, | |
836 0, level->count, true); | |
837 if (r < 0) { | |
838 DMCRIT("an error occurred while reading entry"); | |
839 goto out; | |
840 } | |
841 | |
842 for (i = 0; i < level->count; i++, entry++) { | 806 for (i = 0; i < level->count; i++, entry++) { |
843 unsigned int count = bht->node_count; | 807 unsigned int count = bht->node_count; |
| 808 |
| 809 r = dm_bht_maybe_read_entry(bht, read_cb_ctx, depth, i); |
| 810 if (r < 0) { |
| 811 DMCRIT("an error occurred while reading entry"); |
| 812 goto out; |
| 813 } |
| 814 |
844 if (i == (level->count - 1)) | 815 if (i == (level->count - 1)) |
845 count = child_level->count % bht->node_count; | 816 count = child_level->count % bht->node_count; |
846 if (count == 0) | 817 if (count == 0) |
847 count = bht->node_count; | 818 count = bht->node_count; |
848 for (j = 0; j < count; j++, child++) { | 819 for (j = 0; j < count; j++, child++) { |
849 u8 *block = child->nodes; | 820 u8 *block = child->nodes; |
850 u8 *digest = dm_bht_node(bht, entry, j); | 821 u8 *digest = dm_bht_node(bht, entry, j); |
851 | 822 |
852 r = dm_bht_compute_hash(bht, block, digest); | 823 r = dm_bht_compute_hash(bht, block, digest); |
853 if (r) { | 824 if (r) { |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 | 940 |
970 /* Load in all of level 0 if the root is unverified */ | 941 /* Load in all of level 0 if the root is unverified */ |
971 root_state = atomic_read(&bht->root_state); | 942 root_state = atomic_read(&bht->root_state); |
972 /* TODO(wad) create a separate io object for the root request which | 943 /* TODO(wad) create a separate io object for the root request which |
973 * can continue on and be verified and stop making every request | 944 * can continue on and be verified and stop making every request |
974 * check. | 945 * check. |
975 */ | 946 */ |
976 if (root_state != DM_BHT_ENTRY_VERIFIED) { | 947 if (root_state != DM_BHT_ENTRY_VERIFIED) { |
977 DMDEBUG("root data is not yet loaded"); | 948 DMDEBUG("root data is not yet loaded"); |
978 /* If positive, it means some are pending. */ | 949 /* If positive, it means some are pending. */ |
979 » » populated = dm_bht_maybe_read_entries(bht, read_cb_ctx, 0, 0, | 950 » » populated = dm_bht_maybe_read_entry(bht, read_cb_ctx, 0, 0); |
980 » » » » » » bht->levels[0].count, | |
981 » » » » » » true); | |
982 if (populated < 0) { | 951 if (populated < 0) { |
983 DMCRIT("an error occurred while reading level[0]"); | 952 DMCRIT("an error occurred while reading level[0]"); |
984 /* TODO(wad) define std error codes */ | 953 /* TODO(wad) define std error codes */ |
985 return populated; | 954 return populated; |
986 } | 955 } |
987 } | 956 } |
988 | 957 |
989 for (depth = 1; depth < bht->depth; ++depth) { | 958 for (depth = 1; depth < bht->depth; ++depth) { |
990 level = dm_bht_get_level(bht, depth); | 959 level = dm_bht_get_level(bht, depth); |
991 entry_index = dm_bht_index_at_level(bht, depth, | 960 entry_index = dm_bht_index_at_level(bht, depth, |
992 block_index); | 961 block_index); |
993 DMDEBUG("populate for bi=%u on d=%d ei=%u (max=%u)", | 962 DMDEBUG("populate for bi=%u on d=%d ei=%u (max=%u)", |
994 block_index, depth, entry_index, level->count); | 963 block_index, depth, entry_index, level->count); |
995 | 964 |
996 /* Except for the root node case, we should only ever need | 965 /* Except for the root node case, we should only ever need |
997 * to load one entry along the path. | 966 * to load one entry along the path. |
998 */ | 967 */ |
999 » » read_status = dm_bht_maybe_read_entries(bht, read_cb_ctx, | 968 » » read_status = dm_bht_maybe_read_entry(bht, read_cb_ctx, |
1000 » » » » » » » depth, entry_index, | 969 » » » » » » depth, entry_index); |
1001 » » » » » » » 1, false); | |
1002 if (unlikely(read_status < 0)) { | 970 if (unlikely(read_status < 0)) { |
1003 DMCRIT("failure occurred reading entry %u depth %u", | 971 DMCRIT("failure occurred reading entry %u depth %u", |
1004 entry_index, depth); | 972 entry_index, depth); |
1005 return read_status; | 973 return read_status; |
1006 } | 974 } |
1007 /* Accrue return code flags */ | 975 /* Accrue return code flags */ |
1008 populated |= read_status; | 976 populated |= read_status; |
1009 } | 977 } |
1010 | 978 |
1011 /* All nodes are ready. The hash for the block_index can be verified */ | 979 /* All nodes are ready. The hash for the block_index can be verified */ |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1181 if (!bht->root_digest) { | 1149 if (!bht->root_digest) { |
1182 DMERR("no root digest exists to export"); | 1150 DMERR("no root digest exists to export"); |
1183 if (available > 0) | 1151 if (available > 0) |
1184 *hexdigest = 0; | 1152 *hexdigest = 0; |
1185 return -1; | 1153 return -1; |
1186 } | 1154 } |
1187 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); | 1155 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); |
1188 return 0; | 1156 return 0; |
1189 } | 1157 } |
1190 EXPORT_SYMBOL(dm_bht_root_hexdigest); | 1158 EXPORT_SYMBOL(dm_bht_root_hexdigest); |
OLD | NEW |