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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 u8 computed_hex[DM_BHT_MAX_DIGEST_SIZE * 2 + 1]; | 86 u8 computed_hex[DM_BHT_MAX_DIGEST_SIZE * 2 + 1]; |
| 87 dm_bht_bin_to_hex(given, given_hex, bht->digest_size); | 87 dm_bht_bin_to_hex(given, given_hex, bht->digest_size); |
| 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_and_compare: hashes a page of data; compares it to a hash | 96 * dm_bht_compute_and_compare: hashes a page of data; compares it to a hash |
|
Will Drewry
2011/01/11 21:38:45
please update the comment
| |
| 97 */ | 97 */ |
| 98 static int dm_bht_compute_and_compare(struct dm_bht *bht, | 98 static int dm_bht_compute_hash(struct dm_bht *bht, struct hash_desc *hash_desc, |
| 99 » » » » struct hash_desc *hash_desc, | 99 » » » struct page *page, u8 *digest) |
| 100 » » » » struct page *page, | |
| 101 » » » » u8 *expected_digest, | |
| 102 » » » » dm_bht_compare_cb compare_cb) | |
| 103 { | 100 { |
| 104 struct scatterlist sg; | 101 struct scatterlist sg; |
| 105 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; | |
| 106 int result; | |
| 107 | 102 |
| 108 sg_init_table(&sg, 1); | 103 sg_init_table(&sg, 1); |
| 109 sg_set_page(&sg, page, PAGE_SIZE, 0); | 104 sg_set_page(&sg, page, PAGE_SIZE, 0); |
| 110 /* Note, this is synchronous. */ | 105 /* Note, this is synchronous. */ |
| 111 if (crypto_hash_init(hash_desc)) { | 106 if (crypto_hash_init(hash_desc)) { |
| 112 DMCRIT("failed to reinitialize crypto hash (proc:%d)", | 107 DMCRIT("failed to reinitialize crypto hash (proc:%d)", |
| 113 smp_processor_id()); | 108 smp_processor_id()); |
| 114 return -EINVAL; | 109 return -EINVAL; |
| 115 } | 110 } |
| 116 if (crypto_hash_digest(hash_desc, &sg, PAGE_SIZE, digest)) { | 111 if (crypto_hash_digest(hash_desc, &sg, PAGE_SIZE, digest)) { |
| 117 DMCRIT("crypto_hash_digest failed"); | 112 DMCRIT("crypto_hash_digest failed"); |
| 118 return -EINVAL; | 113 return -EINVAL; |
| 119 } | 114 } |
| 120 | 115 |
| 121 » result = compare_cb(bht, expected_digest, digest); | 116 » return 0; |
| 122 #ifdef CONFIG_DM_DEBUG | |
| 123 » if (result) | |
| 124 » » dm_bht_log_mismatch(bht, expected_digest, digest); | |
| 125 #endif | |
| 126 » return result; | |
| 127 } | 117 } |
| 128 | 118 |
| 129 static __always_inline struct dm_bht_level *dm_bht_get_level(struct dm_bht *bht, | 119 static __always_inline struct dm_bht_level *dm_bht_get_level(struct dm_bht *bht, |
| 130 unsigned int depth) | 120 unsigned int depth) |
| 131 { | 121 { |
| 132 return &bht->levels[depth]; | 122 return &bht->levels[depth]; |
| 133 } | 123 } |
| 134 | 124 |
| 135 static __always_inline unsigned int dm_bht_get_level_shift(struct dm_bht *bht, | 125 static __always_inline unsigned int dm_bht_get_level_shift(struct dm_bht *bht, |
| 136 unsigned int depth) | 126 unsigned int depth) |
| (...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 709 return DM_BHT_ENTRY_ERROR_MISMATCH; | 699 return DM_BHT_ENTRY_ERROR_MISMATCH; |
| 710 } | 700 } |
| 711 /* Could do a cmpxchg, but this should be safe. */ | 701 /* Could do a cmpxchg, but this should be safe. */ |
| 712 atomic_set(&bht->root_state, DM_BHT_ENTRY_VERIFIED); | 702 atomic_set(&bht->root_state, DM_BHT_ENTRY_VERIFIED); |
| 713 return 0; | 703 return 0; |
| 714 } | 704 } |
| 715 | 705 |
| 716 /* dm_bht_verify_path | 706 /* dm_bht_verify_path |
| 717 * Verifies the path from block_index to depth=0. Returns 0 on ok. | 707 * Verifies the path from block_index to depth=0. Returns 0 on ok. |
| 718 */ | 708 */ |
| 719 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index, | 709 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index) |
| 720 » » » dm_bht_compare_cb compare_cb) | |
| 721 { | 710 { |
| 722 unsigned int depth = bht->depth - 1; | 711 unsigned int depth = bht->depth - 1; |
| 723 struct dm_bht_entry *entry = dm_bht_get_entry(bht, depth, block_index); | 712 struct dm_bht_entry *entry = dm_bht_get_entry(bht, depth, block_index); |
| 724 struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()]; | 713 struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()]; |
| 725 | 714 |
| 726 while (depth > 0) { | 715 while (depth > 0) { |
| 716 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; | |
| 727 struct dm_bht_entry *parent; | 717 struct dm_bht_entry *parent; |
| 718 struct page *page; | |
| 728 u8 *node; | 719 u8 *node; |
| 729 int state; | 720 int state; |
| 730 | 721 |
| 731 DMDEBUG("verify_path for b=%u on d=%d", block_index, depth); | 722 DMDEBUG("verify_path for b=%u on d=%d", block_index, depth); |
| 732 state = atomic_read(&entry->state); | 723 state = atomic_read(&entry->state); |
| 733 if (state == DM_BHT_ENTRY_VERIFIED) { | 724 if (state == DM_BHT_ENTRY_VERIFIED) { |
| 734 DMDEBUG("verify_path node %u is verified in parent", | 725 DMDEBUG("verify_path node %u is verified in parent", |
| 735 block_index); | 726 block_index); |
| 736 entry = dm_bht_get_entry(bht, --depth, block_index); | 727 entry = dm_bht_get_entry(bht, --depth, block_index); |
| 737 continue; | 728 continue; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 754 | 745 |
| 755 /* We need to check that this entry matches the expected | 746 /* We need to check that this entry matches the expected |
| 756 * hash in the parent->nodes. | 747 * hash in the parent->nodes. |
| 757 */ | 748 */ |
| 758 parent = dm_bht_get_entry(bht, depth - 1, block_index); | 749 parent = dm_bht_get_entry(bht, depth - 1, block_index); |
| 759 /* This call is only safe if all nodes along the path | 750 /* This call is only safe if all nodes along the path |
| 760 * are already populated (i.e. READY) via dm_bht_populate. | 751 * are already populated (i.e. READY) via dm_bht_populate. |
| 761 */ | 752 */ |
| 762 BUG_ON(atomic_read(&parent->state) < DM_BHT_ENTRY_READY); | 753 BUG_ON(atomic_read(&parent->state) < DM_BHT_ENTRY_READY); |
| 763 node = dm_bht_get_node(bht, parent, depth, block_index); | 754 node = dm_bht_get_node(bht, parent, depth, block_index); |
| 755 page = virt_to_page(entry->nodes); | |
| 764 | 756 |
| 765 » » if (dm_bht_compute_and_compare(bht, hash_desc, | 757 » » if (dm_bht_compute_hash(bht, hash_desc,»page, digest) || |
|
Will Drewry
2011/01/11 21:38:45
is there a tab hiding before page or is it a rietv
| |
| 766 » » » » » virt_to_page(entry->nodes), | 758 » » dm_bht_compare_hash(bht, digest, node)) { |
| 767 » » » » » node, compare_cb)) { | |
| 768 DMERR("failed to verify entry's hash against parent " | 759 DMERR("failed to verify entry's hash against parent " |
| 769 "(d=%u,bi=%u)", depth, block_index); | 760 "(d=%u,bi=%u)", depth, block_index); |
| 770 goto mismatch; | 761 goto mismatch; |
| 771 } | 762 } |
| 772 | 763 |
| 773 if (bht->verify_mode != DM_BHT_FULL_REVERIFY) | 764 if (bht->verify_mode != DM_BHT_FULL_REVERIFY) |
| 774 atomic_cmpxchg(&entry->state, | 765 atomic_cmpxchg(&entry->state, |
| 775 DM_BHT_ENTRY_READY, | 766 DM_BHT_ENTRY_READY, |
| 776 DM_BHT_ENTRY_VERIFIED); | 767 DM_BHT_ENTRY_VERIFIED); |
| 777 | 768 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 853 } else if (state <= DM_BHT_ENTRY_ERROR) { | 844 } else if (state <= DM_BHT_ENTRY_ERROR) { |
| 854 DMCRIT("leaf entry for block %u is invalid", | 845 DMCRIT("leaf entry for block %u is invalid", |
| 855 block_index); | 846 block_index); |
| 856 return state; | 847 return state; |
| 857 } else if (state == DM_BHT_ENTRY_PENDING) { | 848 } else if (state == DM_BHT_ENTRY_PENDING) { |
| 858 DMERR("leaf data is pending for block %u", block_index); | 849 DMERR("leaf data is pending for block %u", block_index); |
| 859 return 1; | 850 return 1; |
| 860 } | 851 } |
| 861 | 852 |
| 862 hash_desc = &bht->hash_desc[smp_processor_id()]; | 853 hash_desc = &bht->hash_desc[smp_processor_id()]; |
| 863 » dm_bht_compute_and_compare(bht, hash_desc, virt_to_page(block_data), | 854 » dm_bht_compute_hash(bht, hash_desc, virt_to_page(block_data), |
| 864 » » » » dm_bht_node(bht, entry, node_index), | 855 » » » dm_bht_node(bht, entry, node_index)); |
| 865 » » » » &dm_bht_update_hash); | |
| 866 return 0; | 856 return 0; |
| 867 } | 857 } |
| 868 EXPORT_SYMBOL(dm_bht_store_block); | 858 EXPORT_SYMBOL(dm_bht_store_block); |
| 869 | 859 |
| 870 /** | 860 /** |
| 871 * dm_bht_zeroread_callback - read callback which always returns 0s | 861 * dm_bht_zeroread_callback - read callback which always returns 0s |
| 872 * @ctx: ignored | 862 * @ctx: ignored |
| 873 * @start: ignored | 863 * @start: ignored |
| 874 * @data: buffer to write 0s to | 864 * @data: buffer to write 0s to |
| 875 * @count: number of sectors worth of data to write | 865 * @count: number of sectors worth of data to write |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 924 if (r < 0) { | 914 if (r < 0) { |
| 925 DMCRIT("an error occurred while reading entry"); | 915 DMCRIT("an error occurred while reading entry"); |
| 926 goto out; | 916 goto out; |
| 927 } | 917 } |
| 928 | 918 |
| 929 for (i = 0; i < level->count; i++, entry++) { | 919 for (i = 0; i < level->count; i++, entry++) { |
| 930 for (j = 0; j < count; j++, child++) { | 920 for (j = 0; j < count; j++, child++) { |
| 931 struct page *pg = virt_to_page(child->nodes); | 921 struct page *pg = virt_to_page(child->nodes); |
| 932 u8 *node = dm_bht_node(bht, entry, j); | 922 u8 *node = dm_bht_node(bht, entry, j); |
| 933 | 923 |
| 934 » » » » r = dm_bht_compute_and_compare(bht, hash_desc, | 924 » » » » r = dm_bht_compute_hash(bht, hash_desc, |
| 935 » » » » » » pg, node, dm_bht_update_hash); | 925 » » » » » » » pg, node); |
| 936 if (r) { | 926 if (r) { |
| 937 DMERR("Failed to update (d=%u,i=%u)", | 927 DMERR("Failed to update (d=%u,i=%u)", |
| 938 depth, i); | 928 depth, i); |
| 939 goto out; | 929 goto out; |
| 940 } | 930 } |
| 941 } | 931 } |
| 942 } | 932 } |
| 943 } | 933 } |
| 944 /* Don't forget the root digest! */ | 934 /* Don't forget the root digest! */ |
| 945 DMDEBUG("Calling verify_root with update_hash"); | 935 DMDEBUG("Calling verify_root with update_hash"); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1133 /* If the entry which contains the block hash is marked verified, then | 1123 /* If the entry which contains the block hash is marked verified, then |
| 1134 * it means that its hash has been check with the parent. In addition, | 1124 * it means that its hash has been check with the parent. In addition, |
| 1135 * since that is only possible via verify_path, it transitively means | 1125 * since that is only possible via verify_path, it transitively means |
| 1136 * it is verified to the root of the tree. If the depth is 1, then it | 1126 * it is verified to the root of the tree. If the depth is 1, then it |
| 1137 * means the entry was verified during root verification. | 1127 * means the entry was verified during root verification. |
| 1138 */ | 1128 */ |
| 1139 if (entry_state == DM_BHT_ENTRY_VERIFIED || bht->depth == 1) | 1129 if (entry_state == DM_BHT_ENTRY_VERIFIED || bht->depth == 1) |
| 1140 return unverified; | 1130 return unverified; |
| 1141 | 1131 |
| 1142 /* Now check levels in between */ | 1132 /* Now check levels in between */ |
| 1143 » unverified = dm_bht_verify_path(bht, | 1133 » unverified = dm_bht_verify_path(bht, block_index); |
| 1144 » » » » » block_index, | |
| 1145 » » » » » dm_bht_compare_hash); | |
| 1146 if (unverified) | 1134 if (unverified) |
| 1147 DMERR_LIMIT("Failed to verify intermediary nodes for block: %u ( %d)", | 1135 DMERR_LIMIT("Failed to verify intermediary nodes for block: %u ( %d)", |
| 1148 block_index, unverified); | 1136 block_index, unverified); |
| 1149 return unverified; | 1137 return unverified; |
| 1150 } | 1138 } |
| 1151 EXPORT_SYMBOL(dm_bht_verify_block); | 1139 EXPORT_SYMBOL(dm_bht_verify_block); |
| 1152 | 1140 |
| 1153 /** | 1141 /** |
| 1154 * dm_bht_destroy - cleans up all memory used by @bht | 1142 * dm_bht_destroy - cleans up all memory used by @bht |
| 1155 * @bht: pointer to a dm_bht_create()d bht | 1143 * @bht: pointer to a dm_bht_create()d bht |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1306 DMERR("no root digest exists to export"); | 1294 DMERR("no root digest exists to export"); |
| 1307 if (available > 0) | 1295 if (available > 0) |
| 1308 *hexdigest = 0; | 1296 *hexdigest = 0; |
| 1309 return -1; | 1297 return -1; |
| 1310 } | 1298 } |
| 1311 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); | 1299 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); |
| 1312 return 0; | 1300 return 0; |
| 1313 } | 1301 } |
| 1314 EXPORT_SYMBOL(dm_bht_root_hexdigest); | 1302 EXPORT_SYMBOL(dm_bht_root_hexdigest); |
| 1315 | 1303 |
| OLD | NEW |