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> |
11 #include <asm/page.h> | 11 #include <asm/page.h> |
12 #include <linux/bitops.h> /* for fls() */ | 12 #include <linux/bitops.h> /* for fls() */ |
13 #include <linux/bug.h> | 13 #include <linux/bug.h> |
14 #include <linux/cpumask.h> /* nr_cpu_ids */ | 14 #include <linux/cpumask.h> /* nr_cpu_ids */ |
15 /* #define CONFIG_DM_DEBUG 1 */ | 15 /* #define CONFIG_DM_DEBUG 1 */ |
16 #include <linux/device-mapper.h> | 16 #include <linux/device-mapper.h> |
17 #include <linux/err.h> | 17 #include <linux/err.h> |
18 #include <linux/errno.h> | 18 #include <linux/errno.h> |
19 #include <linux/gfp.h> | 19 #include <linux/gfp.h> |
20 #include <linux/dm-bht.h> | 20 #include <linux/dm-bht.h> |
21 #include <linux/kernel.h> | 21 #include <linux/kernel.h> |
22 #include <linux/module.h> | 22 #include <linux/module.h> |
| 23 #include <linux/mm_types.h> |
23 #include <linux/scatterlist.h> | 24 #include <linux/scatterlist.h> |
24 #include <linux/slab.h> /* k*alloc */ | 25 #include <linux/slab.h> /* k*alloc */ |
25 #include <linux/string.h> /* memset */ | 26 #include <linux/string.h> /* memset */ |
26 | 27 |
27 #define DM_MSG_PREFIX "dm bht" | 28 #define DM_MSG_PREFIX "dm bht" |
28 | 29 |
29 /* For sector formatting. */ | 30 /* For sector formatting. */ |
30 #if defined(_LP64) || defined(__LP64__) || __BITS_PER_LONG == 64 | 31 #if defined(_LP64) || defined(__LP64__) || __BITS_PER_LONG == 64 |
31 #define __PRIS_PREFIX "z" | 32 #define __PRIS_PREFIX "z" |
32 #else | 33 #else |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 dm_bht_bin_to_hex(computed, computed_hex, bht->digest_size); | 89 dm_bht_bin_to_hex(computed, computed_hex, bht->digest_size); |
89 DMERR_LIMIT("%s != %s", given_hex, computed_hex); | 90 DMERR_LIMIT("%s != %s", given_hex, computed_hex); |
90 } | 91 } |
91 | 92 |
92 /* Used for turning verifiers into computers */ | 93 /* Used for turning verifiers into computers */ |
93 typedef int (*dm_bht_compare_cb)(struct dm_bht *, u8 *, u8 *); | 94 typedef int (*dm_bht_compare_cb)(struct dm_bht *, u8 *, u8 *); |
94 | 95 |
95 /** | 96 /** |
96 * dm_bht_compute_hash: hashes a page of data | 97 * dm_bht_compute_hash: hashes a page of data |
97 */ | 98 */ |
98 static int dm_bht_compute_hash(struct dm_bht *bht, const void *block, | 99 static int dm_bht_compute_hash(struct dm_bht *bht, struct page *pg, |
99 » » » u8 *digest) | 100 » » » unsigned int offset, u8 *digest) |
100 { | 101 { |
101 struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()]; | 102 struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()]; |
102 struct scatterlist sg; | 103 struct scatterlist sg; |
103 | 104 |
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); | 105 sg_init_table(&sg, 1); |
115 » sg_set_buf(&sg, block, PAGE_SIZE); | 106 » sg_set_page(&sg, pg, PAGE_SIZE, offset); |
116 /* Note, this is synchronous. */ | 107 /* Note, this is synchronous. */ |
117 if (crypto_hash_init(hash_desc)) { | 108 if (crypto_hash_init(hash_desc)) { |
118 DMCRIT("failed to reinitialize crypto hash (proc:%d)", | 109 DMCRIT("failed to reinitialize crypto hash (proc:%d)", |
119 smp_processor_id()); | 110 smp_processor_id()); |
120 return -EINVAL; | 111 return -EINVAL; |
121 } | 112 } |
122 if (crypto_hash_digest(hash_desc, &sg, PAGE_SIZE, digest)) { | 113 if (crypto_hash_digest(hash_desc, &sg, PAGE_SIZE, digest)) { |
123 DMCRIT("crypto_hash_digest failed"); | 114 DMCRIT("crypto_hash_digest failed"); |
124 return -EINVAL; | 115 return -EINVAL; |
125 } | 116 } |
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 } | 637 } |
647 /* Could do a cmpxchg, but this should be safe. */ | 638 /* Could do a cmpxchg, but this should be safe. */ |
648 atomic_set(&bht->root_state, DM_BHT_ENTRY_VERIFIED); | 639 atomic_set(&bht->root_state, DM_BHT_ENTRY_VERIFIED); |
649 return 0; | 640 return 0; |
650 } | 641 } |
651 | 642 |
652 /* dm_bht_verify_path | 643 /* dm_bht_verify_path |
653 * Verifies the path. Returns 0 on ok. | 644 * Verifies the path. Returns 0 on ok. |
654 */ | 645 */ |
655 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index, | 646 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index, |
656 » » » const void *block) | 647 » » » struct page *pg, unsigned int offset) |
657 { | 648 { |
658 unsigned int depth = bht->depth; | 649 unsigned int depth = bht->depth; |
659 struct dm_bht_entry *entry; | 650 struct dm_bht_entry *entry; |
660 int state; | 651 int state; |
661 | 652 |
662 do { | 653 do { |
663 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; | 654 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; |
664 u8 *node; | 655 u8 *node; |
665 | 656 |
666 /* Need to check that the hash of the current block is accurate | 657 /* Need to check that the hash of the current block is accurate |
667 * in its parent. | 658 * in its parent. |
668 */ | 659 */ |
669 entry = dm_bht_get_entry(bht, depth - 1, block_index); | 660 entry = dm_bht_get_entry(bht, depth - 1, block_index); |
670 state = atomic_read(&entry->state); | 661 state = atomic_read(&entry->state); |
671 /* This call is only safe if all nodes along the path | 662 /* This call is only safe if all nodes along the path |
672 * are already populated (i.e. READY) via dm_bht_populate. | 663 * are already populated (i.e. READY) via dm_bht_populate. |
673 */ | 664 */ |
674 BUG_ON(state < DM_BHT_ENTRY_READY); | 665 BUG_ON(state < DM_BHT_ENTRY_READY); |
675 node = dm_bht_get_node(bht, entry, depth, block_index); | 666 node = dm_bht_get_node(bht, entry, depth, block_index); |
676 | 667 |
677 » » if (dm_bht_compute_hash(bht, block, digest) || | 668 » » if (dm_bht_compute_hash(bht, pg, offset, digest) || |
678 dm_bht_compare_hash(bht, digest, node)) | 669 dm_bht_compare_hash(bht, digest, node)) |
679 goto mismatch; | 670 goto mismatch; |
680 | 671 |
681 /* Keep the containing block of hashes to be verified in the | 672 /* Keep the containing block of hashes to be verified in the |
682 * next pass. | 673 * next pass. |
683 */ | 674 */ |
684 » » block = entry->nodes; | 675 » » pg = virt_to_page(entry->nodes); |
| 676 » » offset = 0; |
685 } while (--depth > 0 && state != DM_BHT_ENTRY_VERIFIED); | 677 } while (--depth > 0 && state != DM_BHT_ENTRY_VERIFIED); |
686 | 678 |
687 /* Mark path to leaf as verified. */ | 679 /* Mark path to leaf as verified. */ |
688 for (depth++; depth < bht->depth; depth++) { | 680 for (depth++; depth < bht->depth; depth++) { |
689 entry = dm_bht_get_entry(bht, depth, block_index); | 681 entry = dm_bht_get_entry(bht, depth, block_index); |
690 /* At this point, entry can only be in VERIFIED or READY state. | 682 /* 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. | 683 * So it is safe to use atomic_set instead of atomic_cmpxchg. |
692 */ | 684 */ |
693 atomic_set(&entry->state, DM_BHT_ENTRY_VERIFIED); | 685 atomic_set(&entry->state, DM_BHT_ENTRY_VERIFIED); |
694 } | 686 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 atomic_set(&entry->state, DM_BHT_ENTRY_READY); | 761 atomic_set(&entry->state, DM_BHT_ENTRY_READY); |
770 } else if (state <= DM_BHT_ENTRY_ERROR) { | 762 } else if (state <= DM_BHT_ENTRY_ERROR) { |
771 DMCRIT("leaf entry for block %u is invalid", | 763 DMCRIT("leaf entry for block %u is invalid", |
772 block_index); | 764 block_index); |
773 return state; | 765 return state; |
774 } else if (state == DM_BHT_ENTRY_PENDING) { | 766 } else if (state == DM_BHT_ENTRY_PENDING) { |
775 DMERR("leaf data is pending for block %u", block_index); | 767 DMERR("leaf data is pending for block %u", block_index); |
776 return 1; | 768 return 1; |
777 } | 769 } |
778 | 770 |
779 » dm_bht_compute_hash(bht, block_data, | 771 » dm_bht_compute_hash(bht, virt_to_page(block_data), 0, |
780 dm_bht_node(bht, entry, node_index)); | 772 dm_bht_node(bht, entry, node_index)); |
781 return 0; | 773 return 0; |
782 } | 774 } |
783 EXPORT_SYMBOL(dm_bht_store_block); | 775 EXPORT_SYMBOL(dm_bht_store_block); |
784 | 776 |
785 /** | 777 /** |
786 * dm_bht_zeroread_callback - read callback which always returns 0s | 778 * dm_bht_zeroread_callback - read callback which always returns 0s |
787 * @ctx: ignored | 779 * @ctx: ignored |
788 * @start: ignored | 780 * @start: ignored |
789 * @data: buffer to write 0s to | 781 * @data: buffer to write 0s to |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 goto out; | 831 goto out; |
840 } | 832 } |
841 | 833 |
842 for (i = 0; i < level->count; i++, entry++) { | 834 for (i = 0; i < level->count; i++, entry++) { |
843 unsigned int count = bht->node_count; | 835 unsigned int count = bht->node_count; |
844 if (i == (level->count - 1)) | 836 if (i == (level->count - 1)) |
845 count = child_level->count % bht->node_count; | 837 count = child_level->count % bht->node_count; |
846 if (count == 0) | 838 if (count == 0) |
847 count = bht->node_count; | 839 count = bht->node_count; |
848 for (j = 0; j < count; j++, child++) { | 840 for (j = 0; j < count; j++, child++) { |
849 » » » » u8 *block = child->nodes; | 841 » » » » struct page *pg = virt_to_page(child->nodes); |
850 u8 *digest = dm_bht_node(bht, entry, j); | 842 u8 *digest = dm_bht_node(bht, entry, j); |
851 | 843 |
852 » » » » r = dm_bht_compute_hash(bht, block, digest); | 844 » » » » r = dm_bht_compute_hash(bht, pg, 0, digest); |
853 if (r) { | 845 if (r) { |
854 DMERR("Failed to update (d=%u,i=%u)", | 846 DMERR("Failed to update (d=%u,i=%u)", |
855 depth, i); | 847 depth, i); |
856 goto out; | 848 goto out; |
857 } | 849 } |
858 } | 850 } |
859 } | 851 } |
860 } | 852 } |
861 /* Don't forget the root digest! */ | 853 /* Don't forget the root digest! */ |
862 DMDEBUG("Calling verify_root with update_hash"); | 854 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 | 1011 * @bht: pointer to a dm_bht_create()d bht |
1020 * @block_index:specific block data is expected from | 1012 * @block_index:specific block data is expected from |
1021 * @block: virtual address of the block data in memory | 1013 * @block: virtual address of the block data in memory |
1022 * (must be aligned to block size) | 1014 * (must be aligned to block size) |
1023 * | 1015 * |
1024 * Returns 0 on success, 1 on missing data, and a negative error | 1016 * Returns 0 on success, 1 on missing data, and a negative error |
1025 * code on verification failure. All supporting functions called | 1017 * code on verification failure. All supporting functions called |
1026 * should return similarly. | 1018 * should return similarly. |
1027 */ | 1019 */ |
1028 int dm_bht_verify_block(struct dm_bht *bht, unsigned int block_index, | 1020 int dm_bht_verify_block(struct dm_bht *bht, unsigned int block_index, |
1029 » » » const void *block) | 1021 » » » struct page *pg, unsigned int offset) |
1030 { | 1022 { |
1031 int r = 0; | 1023 int r = 0; |
1032 | 1024 |
| 1025 BUG_ON(offset != 0); |
| 1026 |
1033 /* Make sure that the root has been verified */ | 1027 /* Make sure that the root has been verified */ |
1034 if (atomic_read(&bht->root_state) != DM_BHT_ENTRY_VERIFIED) { | 1028 if (atomic_read(&bht->root_state) != DM_BHT_ENTRY_VERIFIED) { |
1035 r = dm_bht_verify_root(bht, dm_bht_compare_hash); | 1029 r = dm_bht_verify_root(bht, dm_bht_compare_hash); |
1036 if (r) { | 1030 if (r) { |
1037 DMERR_LIMIT("Failed to verify root: %d", r); | 1031 DMERR_LIMIT("Failed to verify root: %d", r); |
1038 goto out; | 1032 goto out; |
1039 } | 1033 } |
1040 } | 1034 } |
1041 | 1035 |
1042 /* Now check levels in between */ | 1036 /* Now check levels in between */ |
1043 » r = dm_bht_verify_path(bht, block_index, block); | 1037 » r = dm_bht_verify_path(bht, block_index, pg, offset); |
1044 if (r) | 1038 if (r) |
1045 DMERR_LIMIT("Failed to verify block: %u (%d)", block_index, r); | 1039 DMERR_LIMIT("Failed to verify block: %u (%d)", block_index, r); |
1046 | 1040 |
1047 out: | 1041 out: |
1048 return r; | 1042 return r; |
1049 } | 1043 } |
1050 EXPORT_SYMBOL(dm_bht_verify_block); | 1044 EXPORT_SYMBOL(dm_bht_verify_block); |
1051 | 1045 |
1052 /** | 1046 /** |
1053 * dm_bht_destroy - cleans up all memory used by @bht | 1047 * 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) { | 1175 if (!bht->root_digest) { |
1182 DMERR("no root digest exists to export"); | 1176 DMERR("no root digest exists to export"); |
1183 if (available > 0) | 1177 if (available > 0) |
1184 *hexdigest = 0; | 1178 *hexdigest = 0; |
1185 return -1; | 1179 return -1; |
1186 } | 1180 } |
1187 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); | 1181 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); |
1188 return 0; | 1182 return 0; |
1189 } | 1183 } |
1190 EXPORT_SYMBOL(dm_bht_root_hexdigest); | 1184 EXPORT_SYMBOL(dm_bht_root_hexdigest); |
OLD | NEW |