Chromium Code Reviews| 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 dm_bht_bin_to_hex(computed, computed_hex, bht->digest_size); | 88 dm_bht_bin_to_hex(computed, computed_hex, bht->digest_size); |
| 89 DMERR_LIMIT("%s != %s", given_hex, computed_hex); | 89 DMERR_LIMIT("%s != %s", given_hex, computed_hex); |
| 90 } | 90 } |
| 91 | 91 |
| 92 /* Used for turning verifiers into computers */ | 92 /* Used for turning verifiers into computers */ |
| 93 typedef int (*dm_bht_compare_cb)(struct dm_bht *, u8 *, u8 *); | 93 typedef int (*dm_bht_compare_cb)(struct dm_bht *, u8 *, u8 *); |
| 94 | 94 |
| 95 /** | 95 /** |
| 96 * dm_bht_compute_hash: hashes a page of data | 96 * dm_bht_compute_hash: hashes a page of data |
| 97 */ | 97 */ |
| 98 static int dm_bht_compute_hash(struct dm_bht *bht, const void *block, | 98 static int dm_bht_compute_hash(struct dm_bht *bht, struct page *pg, |
| 99 » » » u8 *digest) | 99 » » » unsigned int offset, u8 *digest) |
| 100 { | 100 { |
| 101 struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()]; | 101 struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()]; |
| 102 struct scatterlist sg; | 102 struct scatterlist sg; |
| 103 | 103 |
| 104 /* TODO(msb): Once we supporting block_size < PAGE_SIZE, change this to: | |
| 105 * offset_into_page + length < page_size | |
| 106 * For now just check that block is page-aligned. | |
| 107 */ | |
| 108 /* | |
| 109 * TODO(msb): Re-enable once user-space code is modified to use | |
| 110 * aligned buffers. | |
| 111 * BUG_ON(!IS_ALIGNED((uintptr_t)block, PAGE_SIZE)); | |
| 112 */ | |
| 113 | |
| 114 sg_init_table(&sg, 1); | 104 sg_init_table(&sg, 1); |
| 115 » sg_set_buf(&sg, block, PAGE_SIZE); | 105 » sg_set_page(&sg, pg, PAGE_SIZE, 0); |
|
Will Drewry
2011/04/13 20:19:30
should 0 be the new offset argument? Then the comm
| |
| 116 /* Note, this is synchronous. */ | 106 /* Note, this is synchronous. */ |
| 117 if (crypto_hash_init(hash_desc)) { | 107 if (crypto_hash_init(hash_desc)) { |
| 118 DMCRIT("failed to reinitialize crypto hash (proc:%d)", | 108 DMCRIT("failed to reinitialize crypto hash (proc:%d)", |
| 119 smp_processor_id()); | 109 smp_processor_id()); |
| 120 return -EINVAL; | 110 return -EINVAL; |
| 121 } | 111 } |
| 122 if (crypto_hash_digest(hash_desc, &sg, PAGE_SIZE, digest)) { | 112 if (crypto_hash_digest(hash_desc, &sg, PAGE_SIZE, digest)) { |
| 123 DMCRIT("crypto_hash_digest failed"); | 113 DMCRIT("crypto_hash_digest failed"); |
| 124 return -EINVAL; | 114 return -EINVAL; |
| 125 } | 115 } |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 } | 529 } |
| 540 /* Current entry is claimed for allocation and loading */ | 530 /* Current entry is claimed for allocation and loading */ |
| 541 node_page = (struct page *) mempool_alloc(bht->entry_pool, | 531 node_page = (struct page *) mempool_alloc(bht->entry_pool, |
| 542 GFP_NOIO); | 532 GFP_NOIO); |
| 543 if (!node_page) { | 533 if (!node_page) { |
| 544 DMCRIT("failed to allocate memory for " | 534 DMCRIT("failed to allocate memory for " |
| 545 "entry->nodes from pool"); | 535 "entry->nodes from pool"); |
| 546 return -ENOMEM; | 536 return -ENOMEM; |
| 547 } | 537 } |
| 548 /* dm-bht guarantees page-aligned memory for callbacks. */ | 538 /* dm-bht guarantees page-aligned memory for callbacks. */ |
| 549 entry->nodes = page_address(node_page); | 539 entry->nodes = page_address(node_page); |
|
Will Drewry
2011/04/13 20:19:30
Will this call be a problem?
Paul T
2011/04/13 20:47:55
This must assume the page is mapped. If it is not,
Mandeep Singh Baines
2011/04/13 21:11:16
I clarified the description. page_address is OK on
| |
| 550 /* Let the caller know that not all the data is yet available */ | 540 /* Let the caller know that not all the data is yet available */ |
| 551 status |= DM_BHT_ENTRY_REQUESTED; | 541 status |= DM_BHT_ENTRY_REQUESTED; |
| 552 /* Issue the read callback */ | 542 /* Issue the read callback */ |
| 553 /* TODO(wad) error check callback here too */ | 543 /* TODO(wad) error check callback here too */ |
| 554 DMDEBUG("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " | 544 DMDEBUG("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " |
| 555 "reading %lu", | 545 "reading %lu", |
| 556 depth, index, count, | 546 depth, index, count, |
| 557 (unsigned long)(entry - level->entries)); | 547 (unsigned long)(entry - level->entries)); |
| 558 bht->read_cb(ctx, /* external context */ | 548 bht->read_cb(ctx, /* external context */ |
| 559 current_sector, /* starting sector */ | 549 current_sector, /* starting sector */ |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 646 } | 636 } |
| 647 /* Could do a cmpxchg, but this should be safe. */ | 637 /* Could do a cmpxchg, but this should be safe. */ |
| 648 atomic_set(&bht->root_state, DM_BHT_ENTRY_VERIFIED); | 638 atomic_set(&bht->root_state, DM_BHT_ENTRY_VERIFIED); |
| 649 return 0; | 639 return 0; |
| 650 } | 640 } |
| 651 | 641 |
| 652 /* dm_bht_verify_path | 642 /* dm_bht_verify_path |
| 653 * Verifies the path. Returns 0 on ok. | 643 * Verifies the path. Returns 0 on ok. |
| 654 */ | 644 */ |
| 655 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index, | 645 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index, |
| 656 » » » const void *block) | 646 » » » struct page *pg, unsigned int offset) |
| 657 { | 647 { |
| 658 unsigned int depth = bht->depth; | 648 unsigned int depth = bht->depth; |
| 659 struct dm_bht_entry *entry; | 649 struct dm_bht_entry *entry; |
| 660 int state; | 650 int state; |
| 661 | 651 |
| 662 do { | 652 do { |
| 663 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; | 653 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; |
| 664 u8 *node; | 654 u8 *node; |
| 665 | 655 |
| 666 /* Need to check that the hash of the current block is accurate | 656 /* Need to check that the hash of the current block is accurate |
| 667 * in its parent. | 657 * in its parent. |
| 668 */ | 658 */ |
| 669 entry = dm_bht_get_entry(bht, depth - 1, block_index); | 659 entry = dm_bht_get_entry(bht, depth - 1, block_index); |
| 670 state = atomic_read(&entry->state); | 660 state = atomic_read(&entry->state); |
| 671 /* This call is only safe if all nodes along the path | 661 /* This call is only safe if all nodes along the path |
| 672 * are already populated (i.e. READY) via dm_bht_populate. | 662 * are already populated (i.e. READY) via dm_bht_populate. |
| 673 */ | 663 */ |
| 674 BUG_ON(state < DM_BHT_ENTRY_READY); | 664 BUG_ON(state < DM_BHT_ENTRY_READY); |
| 675 node = dm_bht_get_node(bht, entry, depth, block_index); | 665 node = dm_bht_get_node(bht, entry, depth, block_index); |
| 676 | 666 |
| 677 » » if (dm_bht_compute_hash(bht, block, digest) || | 667 » » if (dm_bht_compute_hash(bht, pg, offset, digest) || |
| 678 dm_bht_compare_hash(bht, digest, node)) | 668 dm_bht_compare_hash(bht, digest, node)) |
| 679 goto mismatch; | 669 goto mismatch; |
| 680 | 670 |
| 681 /* Keep the containing block of hashes to be verified in the | 671 /* Keep the containing block of hashes to be verified in the |
| 682 * next pass. | 672 * next pass. |
| 683 */ | 673 */ |
| 684 » » block = entry->nodes; | 674 » » pg = virt_to_page(entry->nodes); |
|
Will Drewry
2011/04/13 20:19:30
Hrm should we yet-again convert nodes back to a st
Mandeep Singh Baines
2011/04/13 21:11:16
The virt_to_page here is safe because we did not u
| |
| 675 » » offset = 0; | |
| 685 } while (--depth > 0 && state != DM_BHT_ENTRY_VERIFIED); | 676 } while (--depth > 0 && state != DM_BHT_ENTRY_VERIFIED); |
| 686 | 677 |
| 687 /* Mark path to leaf as verified. */ | 678 /* Mark path to leaf as verified. */ |
| 688 for (depth++; depth < bht->depth; depth++) { | 679 for (depth++; depth < bht->depth; depth++) { |
| 689 entry = dm_bht_get_entry(bht, depth, block_index); | 680 entry = dm_bht_get_entry(bht, depth, block_index); |
| 690 /* At this point, entry can only be in VERIFIED or READY state. | 681 /* At this point, entry can only be in VERIFIED or READY state. |
| 691 * So it is safe to use atomic_set instead of atomic_cmpxchg. | 682 * So it is safe to use atomic_set instead of atomic_cmpxchg. |
| 692 */ | 683 */ |
| 693 atomic_set(&entry->state, DM_BHT_ENTRY_VERIFIED); | 684 atomic_set(&entry->state, DM_BHT_ENTRY_VERIFIED); |
| 694 } | 685 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 769 atomic_set(&entry->state, DM_BHT_ENTRY_READY); | 760 atomic_set(&entry->state, DM_BHT_ENTRY_READY); |
| 770 } else if (state <= DM_BHT_ENTRY_ERROR) { | 761 } else if (state <= DM_BHT_ENTRY_ERROR) { |
| 771 DMCRIT("leaf entry for block %u is invalid", | 762 DMCRIT("leaf entry for block %u is invalid", |
| 772 block_index); | 763 block_index); |
| 773 return state; | 764 return state; |
| 774 } else if (state == DM_BHT_ENTRY_PENDING) { | 765 } else if (state == DM_BHT_ENTRY_PENDING) { |
| 775 DMERR("leaf data is pending for block %u", block_index); | 766 DMERR("leaf data is pending for block %u", block_index); |
| 776 return 1; | 767 return 1; |
| 777 } | 768 } |
| 778 | 769 |
| 779 » dm_bht_compute_hash(bht, block_data, | 770 » dm_bht_compute_hash(bht, virt_to_page(block_data), 0, |
|
Olof Johansson
2011/04/13 21:11:57
Currently block_data is guaranteed to be page alig
| |
| 780 dm_bht_node(bht, entry, node_index)); | 771 dm_bht_node(bht, entry, node_index)); |
| 781 return 0; | 772 return 0; |
| 782 } | 773 } |
| 783 EXPORT_SYMBOL(dm_bht_store_block); | 774 EXPORT_SYMBOL(dm_bht_store_block); |
| 784 | 775 |
| 785 /** | 776 /** |
| 786 * dm_bht_zeroread_callback - read callback which always returns 0s | 777 * dm_bht_zeroread_callback - read callback which always returns 0s |
| 787 * @ctx: ignored | 778 * @ctx: ignored |
| 788 * @start: ignored | 779 * @start: ignored |
| 789 * @data: buffer to write 0s to | 780 * @data: buffer to write 0s to |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 839 goto out; | 830 goto out; |
| 840 } | 831 } |
| 841 | 832 |
| 842 for (i = 0; i < level->count; i++, entry++) { | 833 for (i = 0; i < level->count; i++, entry++) { |
| 843 unsigned int count = bht->node_count; | 834 unsigned int count = bht->node_count; |
| 844 if (i == (level->count - 1)) | 835 if (i == (level->count - 1)) |
| 845 count = child_level->count % bht->node_count; | 836 count = child_level->count % bht->node_count; |
| 846 if (count == 0) | 837 if (count == 0) |
| 847 count = bht->node_count; | 838 count = bht->node_count; |
| 848 for (j = 0; j < count; j++, child++) { | 839 for (j = 0; j < count; j++, child++) { |
| 849 » » » » u8 *block = child->nodes; | 840 » » » » struct page *pg = virt_to_page(child->nodes); |
| 850 u8 *digest = dm_bht_node(bht, entry, j); | 841 u8 *digest = dm_bht_node(bht, entry, j); |
| 851 | 842 |
| 852 » » » » r = dm_bht_compute_hash(bht, block, digest); | 843 » » » » r = dm_bht_compute_hash(bht, pg, 0, digest); |
|
Olof Johansson
2011/04/13 21:11:57
Same here, should probably compute offset?
| |
| 853 if (r) { | 844 if (r) { |
| 854 DMERR("Failed to update (d=%u,i=%u)", | 845 DMERR("Failed to update (d=%u,i=%u)", |
| 855 depth, i); | 846 depth, i); |
| 856 goto out; | 847 goto out; |
| 857 } | 848 } |
| 858 } | 849 } |
| 859 } | 850 } |
| 860 } | 851 } |
| 861 /* Don't forget the root digest! */ | 852 /* Don't forget the root digest! */ |
| 862 DMDEBUG("Calling verify_root with update_hash"); | 853 DMDEBUG("Calling verify_root with update_hash"); |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1019 * @bht: pointer to a dm_bht_create()d bht | 1010 * @bht: pointer to a dm_bht_create()d bht |
| 1020 * @block_index:specific block data is expected from | 1011 * @block_index:specific block data is expected from |
| 1021 * @block: virtual address of the block data in memory | 1012 * @block: virtual address of the block data in memory |
| 1022 * (must be aligned to block size) | 1013 * (must be aligned to block size) |
| 1023 * | 1014 * |
| 1024 * Returns 0 on success, 1 on missing data, and a negative error | 1015 * Returns 0 on success, 1 on missing data, and a negative error |
| 1025 * code on verification failure. All supporting functions called | 1016 * code on verification failure. All supporting functions called |
| 1026 * should return similarly. | 1017 * should return similarly. |
| 1027 */ | 1018 */ |
| 1028 int dm_bht_verify_block(struct dm_bht *bht, unsigned int block_index, | 1019 int dm_bht_verify_block(struct dm_bht *bht, unsigned int block_index, |
| 1029 » » » const void *block) | 1020 » » » struct page *pg, unsigned int offset) |
| 1030 { | 1021 { |
| 1031 int r = 0; | 1022 int r = 0; |
| 1032 | 1023 |
| 1033 /* Make sure that the root has been verified */ | 1024 /* Make sure that the root has been verified */ |
| 1034 if (atomic_read(&bht->root_state) != DM_BHT_ENTRY_VERIFIED) { | 1025 if (atomic_read(&bht->root_state) != DM_BHT_ENTRY_VERIFIED) { |
| 1035 r = dm_bht_verify_root(bht, dm_bht_compare_hash); | 1026 r = dm_bht_verify_root(bht, dm_bht_compare_hash); |
| 1036 if (r) { | 1027 if (r) { |
| 1037 DMERR_LIMIT("Failed to verify root: %d", r); | 1028 DMERR_LIMIT("Failed to verify root: %d", r); |
| 1038 goto out; | 1029 goto out; |
| 1039 } | 1030 } |
| 1040 } | 1031 } |
| 1041 | 1032 |
| 1042 /* Now check levels in between */ | 1033 /* Now check levels in between */ |
| 1043 » r = dm_bht_verify_path(bht, block_index, block); | 1034 » r = dm_bht_verify_path(bht, block_index, pg, offset); |
| 1044 if (r) | 1035 if (r) |
| 1045 DMERR_LIMIT("Failed to verify block: %u (%d)", block_index, r); | 1036 DMERR_LIMIT("Failed to verify block: %u (%d)", block_index, r); |
| 1046 | 1037 |
| 1047 out: | 1038 out: |
| 1048 return r; | 1039 return r; |
| 1049 } | 1040 } |
| 1050 EXPORT_SYMBOL(dm_bht_verify_block); | 1041 EXPORT_SYMBOL(dm_bht_verify_block); |
| 1051 | 1042 |
| 1052 /** | 1043 /** |
| 1053 * dm_bht_destroy - cleans up all memory used by @bht | 1044 * dm_bht_destroy - cleans up all memory used by @bht |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1181 if (!bht->root_digest) { | 1172 if (!bht->root_digest) { |
| 1182 DMERR("no root digest exists to export"); | 1173 DMERR("no root digest exists to export"); |
| 1183 if (available > 0) | 1174 if (available > 0) |
| 1184 *hexdigest = 0; | 1175 *hexdigest = 0; |
| 1185 return -1; | 1176 return -1; |
| 1186 } | 1177 } |
| 1187 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); | 1178 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); |
| 1188 return 0; | 1179 return 0; |
| 1189 } | 1180 } |
| 1190 EXPORT_SYMBOL(dm_bht_root_hexdigest); | 1181 EXPORT_SYMBOL(dm_bht_root_hexdigest); |
| OLD | NEW |