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 |