| 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 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 } | 307 } |
| 308 | 308 |
| 309 /* Setup callback stubs */ | 309 /* Setup callback stubs */ |
| 310 bht->read_cb = &dm_bht_read_callback_stub; | 310 bht->read_cb = &dm_bht_read_callback_stub; |
| 311 bht->write_cb = &dm_bht_write_callback_stub; | 311 bht->write_cb = &dm_bht_write_callback_stub; |
| 312 | 312 |
| 313 status = dm_bht_initialize_entries(bht); | 313 status = dm_bht_initialize_entries(bht); |
| 314 if (status) | 314 if (status) |
| 315 goto bad_entries_alloc; | 315 goto bad_entries_alloc; |
| 316 | 316 |
| 317 /* We compute depth such that there is only be 1 block at level 0. */ |
| 318 BUG_ON(bht->levels[0].count != 1); |
| 319 |
| 317 return 0; | 320 return 0; |
| 318 | 321 |
| 319 bad_entries_alloc: | 322 bad_entries_alloc: |
| 320 while (bht->depth-- > 0) | 323 while (bht->depth-- > 0) |
| 321 kfree(bht->levels[bht->depth].entries); | 324 kfree(bht->levels[bht->depth].entries); |
| 322 kfree(bht->levels); | 325 kfree(bht->levels); |
| 323 bad_node_count: | 326 bad_node_count: |
| 324 bad_level_alloc: | 327 bad_level_alloc: |
| 325 bad_block_count: | 328 bad_block_count: |
| 326 kfree(bht->root_digest); | 329 kfree(bht->root_digest); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 { | 466 { |
| 464 if (status) { | 467 if (status) { |
| 465 DMCRIT("an I/O error occurred while writing entry"); | 468 DMCRIT("an I/O error occurred while writing entry"); |
| 466 atomic_set(&entry->state, DM_BHT_ENTRY_ERROR_IO); | 469 atomic_set(&entry->state, DM_BHT_ENTRY_ERROR_IO); |
| 467 /* entry->nodes will be freed later */ | 470 /* entry->nodes will be freed later */ |
| 468 return; | 471 return; |
| 469 } | 472 } |
| 470 } | 473 } |
| 471 EXPORT_SYMBOL(dm_bht_write_completed); | 474 EXPORT_SYMBOL(dm_bht_write_completed); |
| 472 | 475 |
| 476 /* dm_bht_maybe_read_entry |
| 477 * Attempts to atomically acquire an entry, allocate any needed |
| 478 * memory, and issues the I/O callback to load the hash from disk. |
| 479 * Return value is negative on error. When positive, it is the state |
| 480 * value. |
| 481 */ |
| 482 static int dm_bht_maybe_read_entry(struct dm_bht *bht, void *ctx, |
| 483 unsigned int depth, unsigned int index) |
| 484 { |
| 485 struct dm_bht_level *level = &bht->levels[depth]; |
| 486 struct dm_bht_entry *entry = &level->entries[index]; |
| 487 sector_t current_sector = level->sector + to_sector(index * PAGE_SIZE); |
| 488 struct page *node_page; |
| 489 int state; |
| 473 | 490 |
| 474 /* dm_bht_maybe_read_entries | |
| 475 * Attempts to atomically acquire each entry, allocated any needed | |
| 476 * memory, and issues I/O callbacks to load the hashes from disk. | |
| 477 * Returns 0 if all entries are loaded and verified. On error, the | |
| 478 * return value is negative. When positive, it is the state values | |
| 479 * ORd. | |
| 480 */ | |
| 481 static int dm_bht_maybe_read_entries(struct dm_bht *bht, void *ctx, | |
| 482 unsigned int depth, unsigned int index, | |
| 483 unsigned int count, bool until_exist) | |
| 484 { | |
| 485 struct dm_bht_level *level; | |
| 486 struct dm_bht_entry *entry, *last_entry; | |
| 487 sector_t current_sector; | |
| 488 int state = 0; | |
| 489 int status = 0; | |
| 490 struct page *node_page = NULL; | |
| 491 BUG_ON(depth >= bht->depth); | 491 BUG_ON(depth >= bht->depth); |
| 492 | 492 |
| 493 level = &bht->levels[depth]; | |
| 494 if (count > level->count - index) { | |
| 495 DMERR("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " | |
| 496 "index+count exceeds available entries %u", | |
| 497 depth, index, count, level->count); | |
| 498 return -EINVAL; | |
| 499 } | |
| 500 /* XXX: hardcoding PAGE_SIZE means that a perfectly valid image | 493 /* XXX: hardcoding PAGE_SIZE means that a perfectly valid image |
| 501 * on one system may not work on a different kernel. | 494 * on one system may not work on a different kernel. |
| 502 * TODO(wad) abstract PAGE_SIZE with a bht->entry_size or | 495 * TODO(wad) abstract PAGE_SIZE with a bht->entry_size or |
| 503 * at least a define and ensure bht->entry_size is | 496 * at least a define and ensure bht->entry_size is |
| 504 * sector aligned at least. | 497 * sector aligned at least. |
| 505 */ | 498 */ |
| 506 current_sector = level->sector + to_sector(index * PAGE_SIZE); | |
| 507 for (entry = &level->entries[index], last_entry = entry + count; | |
| 508 entry < last_entry; | |
| 509 ++entry, current_sector += to_sector(PAGE_SIZE)) { | |
| 510 /* If the entry's state is UNALLOCATED, then we'll claim it | |
| 511 * for allocation and loading. | |
| 512 */ | |
| 513 state = atomic_cmpxchg(&entry->state, | |
| 514 DM_BHT_ENTRY_UNALLOCATED, | |
| 515 DM_BHT_ENTRY_PENDING); | |
| 516 DMDEBUG("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " | |
| 517 "ei=%lu, state=%d", | |
| 518 depth, index, count, | |
| 519 (unsigned long)(entry - level->entries), state); | |
| 520 if (state <= DM_BHT_ENTRY_ERROR) { | |
| 521 DMCRIT("entry %u is in an error state", index); | |
| 522 return state; | |
| 523 } | |
| 524 | 499 |
| 525 » » /* Currently, the verified state is unused. */ | 500 » /* If the entry's state is UNALLOCATED, then we'll claim it |
| 526 » » if (state == DM_BHT_ENTRY_VERIFIED) { | 501 » * for allocation and loading. |
| 527 » » » if (until_exist) | 502 » */ |
| 528 » » » » return 0; | 503 » state = atomic_cmpxchg(&entry->state, |
| 529 » » » /* Makes 0 == verified. Is that ideal? */ | 504 » » » DM_BHT_ENTRY_UNALLOCATED, |
| 530 » » » continue; | 505 » » » DM_BHT_ENTRY_PENDING); |
| 531 » » } | 506 » DMDEBUG("dm_bht_maybe_read_entry(d=%u,ei=%u): ei=%lu, state=%d", |
| 507 » » depth, index, (unsigned long)(entry - level->entries), state); |
| 532 | 508 |
| 533 » » if (state != DM_BHT_ENTRY_UNALLOCATED) { | 509 » if (state != DM_BHT_ENTRY_UNALLOCATED) |
| 534 » » » /* PENDING, READY, ... */ | 510 » » goto out; |
| 535 » » » if (until_exist) | |
| 536 » » » » return state; | |
| 537 » » » status |= state; | |
| 538 » » » continue; | |
| 539 » » } | |
| 540 » » /* Current entry is claimed for allocation and loading */ | |
| 541 » » node_page = (struct page *) mempool_alloc(bht->entry_pool, | |
| 542 » » » » » » » GFP_NOIO); | |
| 543 » » if (!node_page) { | |
| 544 » » » DMCRIT("failed to allocate memory for " | |
| 545 » » » "entry->nodes from pool"); | |
| 546 » » » return -ENOMEM; | |
| 547 » » } | |
| 548 » » /* dm-bht guarantees page-aligned memory for callbacks. */ | |
| 549 » » entry->nodes = page_address(node_page); | |
| 550 » » /* Let the caller know that not all the data is yet available */ | |
| 551 » » status |= DM_BHT_ENTRY_REQUESTED; | |
| 552 » » /* Issue the read callback */ | |
| 553 » » /* TODO(wad) error check callback here too */ | |
| 554 » » DMDEBUG("dm_bht_maybe_read_entries(d=%u,ei=%u,count=%u): " | |
| 555 » » » "reading %lu", | |
| 556 » » » depth, index, count, | |
| 557 » » » (unsigned long)(entry - level->entries)); | |
| 558 » » bht->read_cb(ctx, /* external context */ | |
| 559 » » » current_sector, /* starting sector */ | |
| 560 » » » entry->nodes, /* destination */ | |
| 561 » » » to_sector(PAGE_SIZE), | |
| 562 » » » entry); /* io context */ | |
| 563 | 511 |
| 564 » } | 512 » state = DM_BHT_ENTRY_REQUESTED; |
| 565 » /* Should only be 0 if all entries were verified and not just ready */ | 513 |
| 566 » return status; | 514 » /* Current entry is claimed for allocation and loading */ |
| 515 » node_page = (struct page *) mempool_alloc(bht->entry_pool, GFP_NOIO); |
| 516 » if (!node_page) |
| 517 » » goto nomem; |
| 518 » /* dm-bht guarantees page-aligned memory for callbacks. */ |
| 519 » entry->nodes = page_address(node_page); |
| 520 |
| 521 » /* TODO(wad) error check callback here too */ |
| 522 » DMDEBUG("dm_bht_maybe_read_entry(d=%u,ei=%u): reading %lu", |
| 523 » » depth, index, (unsigned long)(entry - level->entries)); |
| 524 » bht->read_cb(ctx, current_sector, entry->nodes, |
| 525 » » to_sector(PAGE_SIZE), entry); |
| 526 |
| 527 out: |
| 528 » if (state <= DM_BHT_ENTRY_ERROR) |
| 529 » » DMCRIT("entry %u is in an error state", index); |
| 530 |
| 531 » return state; |
| 532 |
| 533 nomem: |
| 534 » DMCRIT("failed to allocate memory for entry->nodes from pool"); |
| 535 » return -ENOMEM; |
| 536 |
| 537 |
| 567 } | 538 } |
| 568 | 539 |
| 569 static int dm_bht_compare_hash(struct dm_bht *bht, u8 *known, u8 *computed) | 540 static int dm_bht_compare_hash(struct dm_bht *bht, u8 *known, u8 *computed) |
| 570 { | 541 { |
| 571 return memcmp(known, computed, bht->digest_size); | 542 return memcmp(known, computed, bht->digest_size); |
| 572 } | 543 } |
| 573 | 544 |
| 574 static int dm_bht_update_hash(struct dm_bht *bht, u8 *known, u8 *computed) | 545 static int dm_bht_update_hash(struct dm_bht *bht, u8 *known, u8 *computed) |
| 575 { | 546 { |
| 576 #ifdef CONFIG_DM_DEBUG | 547 #ifdef CONFIG_DM_DEBUG |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 { | 796 { |
| 826 int depth, r; | 797 int depth, r; |
| 827 | 798 |
| 828 for (depth = bht->depth - 2; depth >= 0; depth--) { | 799 for (depth = bht->depth - 2; depth >= 0; depth--) { |
| 829 struct dm_bht_level *level = dm_bht_get_level(bht, depth); | 800 struct dm_bht_level *level = dm_bht_get_level(bht, depth); |
| 830 struct dm_bht_level *child_level = level + 1; | 801 struct dm_bht_level *child_level = level + 1; |
| 831 struct dm_bht_entry *entry = level->entries; | 802 struct dm_bht_entry *entry = level->entries; |
| 832 struct dm_bht_entry *child = child_level->entries; | 803 struct dm_bht_entry *child = child_level->entries; |
| 833 unsigned int i, j; | 804 unsigned int i, j; |
| 834 | 805 |
| 835 r = dm_bht_maybe_read_entries(bht, read_cb_ctx, depth, | |
| 836 0, level->count, true); | |
| 837 if (r < 0) { | |
| 838 DMCRIT("an error occurred while reading entry"); | |
| 839 goto out; | |
| 840 } | |
| 841 | |
| 842 for (i = 0; i < level->count; i++, entry++) { | 806 for (i = 0; i < level->count; i++, entry++) { |
| 843 unsigned int count = bht->node_count; | 807 unsigned int count = bht->node_count; |
| 808 |
| 809 r = dm_bht_maybe_read_entry(bht, read_cb_ctx, depth, i); |
| 810 if (r < 0) { |
| 811 DMCRIT("an error occurred while reading entry"); |
| 812 goto out; |
| 813 } |
| 814 |
| 844 if (i == (level->count - 1)) | 815 if (i == (level->count - 1)) |
| 845 count = child_level->count % bht->node_count; | 816 count = child_level->count % bht->node_count; |
| 846 if (count == 0) | 817 if (count == 0) |
| 847 count = bht->node_count; | 818 count = bht->node_count; |
| 848 for (j = 0; j < count; j++, child++) { | 819 for (j = 0; j < count; j++, child++) { |
| 849 u8 *block = child->nodes; | 820 u8 *block = child->nodes; |
| 850 u8 *digest = dm_bht_node(bht, entry, j); | 821 u8 *digest = dm_bht_node(bht, entry, j); |
| 851 | 822 |
| 852 r = dm_bht_compute_hash(bht, block, digest); | 823 r = dm_bht_compute_hash(bht, block, digest); |
| 853 if (r) { | 824 if (r) { |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 969 | 940 |
| 970 /* Load in all of level 0 if the root is unverified */ | 941 /* Load in all of level 0 if the root is unverified */ |
| 971 root_state = atomic_read(&bht->root_state); | 942 root_state = atomic_read(&bht->root_state); |
| 972 /* TODO(wad) create a separate io object for the root request which | 943 /* TODO(wad) create a separate io object for the root request which |
| 973 * can continue on and be verified and stop making every request | 944 * can continue on and be verified and stop making every request |
| 974 * check. | 945 * check. |
| 975 */ | 946 */ |
| 976 if (root_state != DM_BHT_ENTRY_VERIFIED) { | 947 if (root_state != DM_BHT_ENTRY_VERIFIED) { |
| 977 DMDEBUG("root data is not yet loaded"); | 948 DMDEBUG("root data is not yet loaded"); |
| 978 /* If positive, it means some are pending. */ | 949 /* If positive, it means some are pending. */ |
| 979 » » populated = dm_bht_maybe_read_entries(bht, read_cb_ctx, 0, 0, | 950 » » populated = dm_bht_maybe_read_entry(bht, read_cb_ctx, 0, 0); |
| 980 » » » » » » bht->levels[0].count, | |
| 981 » » » » » » true); | |
| 982 if (populated < 0) { | 951 if (populated < 0) { |
| 983 DMCRIT("an error occurred while reading level[0]"); | 952 DMCRIT("an error occurred while reading level[0]"); |
| 984 /* TODO(wad) define std error codes */ | 953 /* TODO(wad) define std error codes */ |
| 985 return populated; | 954 return populated; |
| 986 } | 955 } |
| 987 } | 956 } |
| 988 | 957 |
| 989 for (depth = 1; depth < bht->depth; ++depth) { | 958 for (depth = 1; depth < bht->depth; ++depth) { |
| 990 level = dm_bht_get_level(bht, depth); | 959 level = dm_bht_get_level(bht, depth); |
| 991 entry_index = dm_bht_index_at_level(bht, depth, | 960 entry_index = dm_bht_index_at_level(bht, depth, |
| 992 block_index); | 961 block_index); |
| 993 DMDEBUG("populate for bi=%u on d=%d ei=%u (max=%u)", | 962 DMDEBUG("populate for bi=%u on d=%d ei=%u (max=%u)", |
| 994 block_index, depth, entry_index, level->count); | 963 block_index, depth, entry_index, level->count); |
| 995 | 964 |
| 996 /* Except for the root node case, we should only ever need | 965 /* Except for the root node case, we should only ever need |
| 997 * to load one entry along the path. | 966 * to load one entry along the path. |
| 998 */ | 967 */ |
| 999 » » read_status = dm_bht_maybe_read_entries(bht, read_cb_ctx, | 968 » » read_status = dm_bht_maybe_read_entry(bht, read_cb_ctx, |
| 1000 » » » » » » » depth, entry_index, | 969 » » » » » » depth, entry_index); |
| 1001 » » » » » » » 1, false); | |
| 1002 if (unlikely(read_status < 0)) { | 970 if (unlikely(read_status < 0)) { |
| 1003 DMCRIT("failure occurred reading entry %u depth %u", | 971 DMCRIT("failure occurred reading entry %u depth %u", |
| 1004 entry_index, depth); | 972 entry_index, depth); |
| 1005 return read_status; | 973 return read_status; |
| 1006 } | 974 } |
| 1007 /* Accrue return code flags */ | 975 /* Accrue return code flags */ |
| 1008 populated |= read_status; | 976 populated |= read_status; |
| 1009 } | 977 } |
| 1010 | 978 |
| 1011 /* All nodes are ready. The hash for the block_index can be verified */ | 979 /* All nodes are ready. The hash for the block_index can be verified */ |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1181 if (!bht->root_digest) { | 1149 if (!bht->root_digest) { |
| 1182 DMERR("no root digest exists to export"); | 1150 DMERR("no root digest exists to export"); |
| 1183 if (available > 0) | 1151 if (available > 0) |
| 1184 *hexdigest = 0; | 1152 *hexdigest = 0; |
| 1185 return -1; | 1153 return -1; |
| 1186 } | 1154 } |
| 1187 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); | 1155 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); |
| 1188 return 0; | 1156 return 0; |
| 1189 } | 1157 } |
| 1190 EXPORT_SYMBOL(dm_bht_root_hexdigest); | 1158 EXPORT_SYMBOL(dm_bht_root_hexdigest); |
| OLD | NEW |