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 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 452 { | 452 { |
| 453 if (status) { | 453 if (status) { |
| 454 DMCRIT("an I/O error occurred while writing entry"); | 454 DMCRIT("an I/O error occurred while writing entry"); |
| 455 atomic_set(&entry->state, DM_BHT_ENTRY_ERROR_IO); | 455 atomic_set(&entry->state, DM_BHT_ENTRY_ERROR_IO); |
| 456 /* entry->nodes will be freed later */ | 456 /* entry->nodes will be freed later */ |
| 457 return; | 457 return; |
| 458 } | 458 } |
| 459 } | 459 } |
| 460 EXPORT_SYMBOL(dm_bht_write_completed); | 460 EXPORT_SYMBOL(dm_bht_write_completed); |
| 461 | 461 |
| 462 /* dm_bht_maybe_read_entry | |
| 463 * Attempts to atomically acquire an entry, allocate any needed | |
| 464 * memory, and issues the I/O callback to load the hash from disk. | |
| 465 * Return value is negative on error. When positive, it is the state | |
| 466 * value. | |
| 467 */ | |
| 468 static int dm_bht_maybe_read_entry(struct dm_bht *bht, void *ctx, | |
| 469 unsigned int depth, unsigned int index) | |
| 470 { | |
| 471 struct dm_bht_level *level = &bht->levels[depth]; | |
| 472 struct dm_bht_entry *entry = &level->entries[index]; | |
| 473 sector_t current_sector = level->sector + to_sector(index * PAGE_SIZE); | |
| 474 struct page *node_page; | |
| 475 int state; | |
| 476 | |
| 477 BUG_ON(depth >= bht->depth); | |
| 478 | |
| 479 /* XXX: hardcoding PAGE_SIZE means that a perfectly valid image | |
| 480 * on one system may not work on a different kernel. | |
| 481 * TODO(wad) abstract PAGE_SIZE with a bht->entry_size or | |
| 482 * at least a define and ensure bht->entry_size is | |
| 483 * sector aligned at least. | |
| 484 */ | |
| 485 | |
| 486 /* If the entry's state is UNALLOCATED, then we'll claim it | |
| 487 * for allocation and loading. | |
| 488 */ | |
| 489 state = atomic_cmpxchg(&entry->state, | |
| 490 DM_BHT_ENTRY_UNALLOCATED, | |
| 491 DM_BHT_ENTRY_PENDING); | |
| 492 DMDEBUG("dm_bht_maybe_read_entry(d=%u,ei=%u): ei=%lu, state=%d", | |
| 493 depth, index, (unsigned long)(entry - level->entries), state); | |
| 494 | |
| 495 if (state != DM_BHT_ENTRY_UNALLOCATED) | |
| 496 goto out; | |
| 497 | |
| 498 state = DM_BHT_ENTRY_REQUESTED; | |
| 499 | |
| 500 /* Current entry is claimed for allocation and loading */ | |
| 501 node_page = (struct page *) mempool_alloc(bht->entry_pool, GFP_NOIO); | |
| 502 if (!node_page) | |
| 503 goto nomem; | |
| 504 /* dm-bht guarantees page-aligned memory for callbacks. */ | |
| 505 entry->nodes = page_address(node_page); | |
| 506 | |
| 507 /* TODO(wad) error check callback here too */ | |
| 508 DMDEBUG("dm_bht_maybe_read_entry(d=%u,ei=%u): reading %lu", | |
| 509 depth, index, (unsigned long)(entry - level->entries)); | |
| 510 bht->read_cb(ctx, current_sector, entry->nodes, | |
| 511 to_sector(PAGE_SIZE), entry); | |
| 512 | |
| 513 out: | |
| 514 if (state <= DM_BHT_ENTRY_ERROR) | |
| 515 DMCRIT("entry %u is in an error state", index); | |
| 516 | |
| 517 return state; | |
| 518 | |
| 519 nomem: | |
| 520 DMCRIT("failed to allocate memory for entry->nodes from pool"); | |
| 521 return -ENOMEM; | |
| 522 | |
| 523 | |
| 524 } | |
| 525 | |
| 526 /* dm_bht_verify_path | 462 /* dm_bht_verify_path |
| 527 * Verifies the path. Returns 0 on ok. | 463 * Verifies the path. Returns 0 on ok. |
| 528 */ | 464 */ |
| 529 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index, | 465 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index, |
| 530 struct page *pg, unsigned int offset) | 466 struct page *pg, unsigned int offset) |
| 531 { | 467 { |
| 532 unsigned int depth = bht->depth; | 468 unsigned int depth = bht->depth; |
| 533 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; | 469 u8 digest[DM_BHT_MAX_DIGEST_SIZE]; |
| 534 struct dm_bht_entry *entry; | 470 struct dm_bht_entry *entry; |
| 535 u8 *node; | 471 u8 *node; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 709 | 645 |
| 710 for (depth = bht->depth - 2; depth >= 0; depth--) { | 646 for (depth = bht->depth - 2; depth >= 0; depth--) { |
| 711 struct dm_bht_level *level = dm_bht_get_level(bht, depth); | 647 struct dm_bht_level *level = dm_bht_get_level(bht, depth); |
| 712 struct dm_bht_level *child_level = level + 1; | 648 struct dm_bht_level *child_level = level + 1; |
| 713 struct dm_bht_entry *entry = level->entries; | 649 struct dm_bht_entry *entry = level->entries; |
| 714 struct dm_bht_entry *child = child_level->entries; | 650 struct dm_bht_entry *child = child_level->entries; |
| 715 unsigned int i, j; | 651 unsigned int i, j; |
| 716 | 652 |
| 717 for (i = 0; i < level->count; i++, entry++) { | 653 for (i = 0; i < level->count; i++, entry++) { |
| 718 unsigned int count = bht->node_count; | 654 unsigned int count = bht->node_count; |
| 655 struct page *pg; | |
| 719 | 656 |
| 720 » » » r = dm_bht_maybe_read_entry(bht, read_cb_ctx, depth, i); | 657 » » » pg = (struct page *) mempool_alloc(bht->entry_pool, |
| 721 » » » if (r < 0) { | 658 » » » » » » » GFP_NOIO); |
| 659 » » » if (!pg) { | |
| 722 DMCRIT("an error occurred while reading entry"); | 660 DMCRIT("an error occurred while reading entry"); |
| 723 goto out; | 661 goto out; |
| 724 } | 662 } |
| 725 | 663 |
| 664 entry->nodes = page_address(pg); | |
| 665 atomic_set(&entry->state, DM_BHT_ENTRY_READY); | |
| 666 | |
| 726 if (i == (level->count - 1)) | 667 if (i == (level->count - 1)) |
| 727 count = child_level->count % bht->node_count; | 668 count = child_level->count % bht->node_count; |
| 728 if (count == 0) | 669 if (count == 0) |
| 729 count = bht->node_count; | 670 count = bht->node_count; |
| 730 for (j = 0; j < count; j++, child++) { | 671 for (j = 0; j < count; j++, child++) { |
| 731 struct page *pg = virt_to_page(child->nodes); | 672 struct page *pg = virt_to_page(child->nodes); |
| 732 u8 *digest = dm_bht_node(bht, entry, j); | 673 u8 *digest = dm_bht_node(bht, entry, j); |
| 733 | 674 |
| 734 r = dm_bht_compute_hash(bht, pg, 0, digest); | 675 r = dm_bht_compute_hash(bht, pg, 0, digest); |
| 735 if (r) { | 676 if (r) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 820 return false; | 761 return false; |
| 821 } | 762 } |
| 822 | 763 |
| 823 return true; | 764 return true; |
| 824 } | 765 } |
| 825 EXPORT_SYMBOL(dm_bht_is_populated); | 766 EXPORT_SYMBOL(dm_bht_is_populated); |
| 826 | 767 |
| 827 /** | 768 /** |
| 828 * dm_bht_populate - reads entries from disk needed to verify a given block | 769 * dm_bht_populate - reads entries from disk needed to verify a given block |
| 829 * @bht: pointer to a dm_bht_create()d bht | 770 * @bht: pointer to a dm_bht_create()d bht |
| 830 * @read_cb_ctx:context used for all read_cb calls on this request | 771 * @ctx: context used for all read_cb calls on this request |
| 831 * @block_index:specific block data is expected from | 772 * @block_index:specific block data is expected from |
| 832 * | 773 * |
| 833 * Returns negative value on error. | 774 * Returns negative value on error. Returns 0 on success. |
| 834 */ | 775 */ |
| 835 int dm_bht_populate(struct dm_bht *bht, void *read_cb_ctx, | 776 int dm_bht_populate(struct dm_bht *bht, void *ctx, |
| 836 unsigned int block_index) | 777 unsigned int block_index) |
| 837 { | 778 { |
| 838 » unsigned int depth, entry_index; | 779 » unsigned int depth; |
| 839 » int status, populated = 0; | 780 » int state = 0; |
| 840 | 781 |
| 841 BUG_ON(block_index >= bht->block_count); | 782 BUG_ON(block_index >= bht->block_count); |
| 842 | 783 |
| 843 DMDEBUG("dm_bht_populate(%u)", block_index); | 784 DMDEBUG("dm_bht_populate(%u)", block_index); |
| 844 | 785 |
| 845 for (depth = 0; depth < bht->depth; ++depth) { | 786 for (depth = 0; depth < bht->depth; ++depth) { |
| 846 » » entry_index = dm_bht_index_at_level(bht, depth, block_index); | 787 » » struct dm_bht_level *level; |
| 847 » » status = dm_bht_maybe_read_entry(bht, read_cb_ctx, depth, | 788 » » struct dm_bht_entry *entry; |
| 848 » » » » » » entry_index); | 789 » » unsigned int index; |
| 849 » » if (status < 0) | 790 » » struct page *pg; |
| 850 » » » goto read_error; | |
| 851 | 791 |
| 852 » » /* Accrue return code flags */ | 792 » » entry = dm_bht_get_entry(bht, depth, block_index); |
| 853 » » populated |= status; | 793 » » state = atomic_cmpxchg(&entry->state, |
| 794 » » » » DM_BHT_ENTRY_UNALLOCATED, | |
| 795 » » » » DM_BHT_ENTRY_PENDING); | |
| 796 | |
| 797 » » if (state <= DM_BHT_ENTRY_ERROR) | |
| 798 » » » goto error_state; | |
| 799 | |
| 800 » » if (state != DM_BHT_ENTRY_UNALLOCATED) | |
| 801 » » » continue; | |
| 802 | |
| 803 » » /* Current entry is claimed for allocation and loading */ | |
| 804 » » pg = (struct page *) mempool_alloc(bht->entry_pool, GFP_NOIO); | |
| 805 » » if (!pg) | |
| 806 » » » goto nomem; | |
| 807 | |
| 808 » » /* dm-bht guarantees page-aligned memory for callbacks. */ | |
| 809 » » entry->nodes = page_address(pg); | |
| 810 | |
| 811 » » /* TODO(wad) error check callback here too */ | |
| 812 | |
| 813 » » level = &bht->levels[depth]; | |
| 814 » » index = dm_bht_index_at_level(bht, depth, block_index); | |
| 815 » » bht->read_cb(ctx, level->sector + to_sector(index * PAGE_SIZE), | |
| 816 » » » entry->nodes, to_sector(PAGE_SIZE), entry); | |
| 854 } | 817 } |
| 855 | 818 |
| 856 » return populated; | 819 » return 0; |
| 857 | 820 |
| 858 read_error: | 821 error_state: |
| 859 » DMCRIT("failure reading entry %u depth %u", entry_index, depth); | 822 » DMCRIT("block %u at depth %u is in an error state", block_index, depth); |
|
Paul T
2011/07/19 15:00:51
Why not add the state to the error message?
| |
| 860 » return status; | 823 » return state; |
| 861 | 824 |
| 825 nomem: | |
| 826 DMCRIT("failed to allocate memory for entry->nodes from pool"); | |
| 827 return -ENOMEM; | |
| 862 } | 828 } |
| 863 EXPORT_SYMBOL(dm_bht_populate); | 829 EXPORT_SYMBOL(dm_bht_populate); |
| 864 | 830 |
| 865 | 831 |
| 866 /** | 832 /** |
| 867 * dm_bht_verify_block - checks that all nodes in the path for @block are valid | 833 * dm_bht_verify_block - checks that all nodes in the path for @block are valid |
| 868 * @bht: pointer to a dm_bht_create()d bht | 834 * @bht: pointer to a dm_bht_create()d bht |
| 869 * @block_index:specific block data is expected from | 835 * @block_index:specific block data is expected from |
| 870 * @block: virtual address of the block data in memory | 836 * @block: virtual address of the block data in memory |
| 871 * (must be aligned to block size) | 837 * (must be aligned to block size) |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1011 if (!bht->root_digest) { | 977 if (!bht->root_digest) { |
| 1012 DMERR("no root digest exists to export"); | 978 DMERR("no root digest exists to export"); |
| 1013 if (available > 0) | 979 if (available > 0) |
| 1014 *hexdigest = 0; | 980 *hexdigest = 0; |
| 1015 return -1; | 981 return -1; |
| 1016 } | 982 } |
| 1017 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); | 983 dm_bht_bin_to_hex(bht->root_digest, hexdigest, bht->digest_size); |
| 1018 return 0; | 984 return 0; |
| 1019 } | 985 } |
| 1020 EXPORT_SYMBOL(dm_bht_root_hexdigest); | 986 EXPORT_SYMBOL(dm_bht_root_hexdigest); |
| OLD | NEW |