| 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 |