verity: remove write callback from user-space
Remove the write callback abstraction as it is no longer needed.
BUG=chromium-os:19952
TEST=Ran unit tests from dm-verity.git.
Ran platform_DMVerityCorruption and platform_DMVerityBitCorruption.
TESTED_ON=Alex
Change-Id: I111c1a5d6a21b1da594a24c94c36af71fca2f816
Reviewed-on: http://gerrit.chromium.org/gerrit/7102
Reviewed-by: Mandeep Singh Baines <msb@chromium.org>
Tested-by: Mandeep Singh Baines <msb@chromium.org>
diff --git a/dm-bht-userspace.c b/dm-bht-userspace.c
index e495fd5..247245d 100644
--- a/dm-bht-userspace.c
+++ b/dm-bht-userspace.c
@@ -53,23 +53,33 @@
return 0;
}
+void dm_bht_set_buffer(struct dm_bht *bht, void *buffer) {
+ int depth;
+
+ for (depth = 0; depth < bht->depth; ++depth) {
+ struct dm_bht_level *level = dm_bht_get_level(bht, depth);
+ struct dm_bht_entry *entry_end = level->entries + level->count;
+ struct dm_bht_entry *entry;
+
+ for (entry = level->entries; entry < entry_end; ++entry) {
+ entry->nodes = buffer;
+ memset(buffer, 0, PAGE_SIZE);
+ buffer += PAGE_SIZE;
+ }
+ }
+}
+
/**
* dm_bht_compute - computes and updates all non-block-level hashes in a tree
* @bht: pointer to a dm_bht_create()d bht
- * @read_cb_ctx:opaque read_cb context for all I/O on this call
*
* Returns 0 on success, >0 when data is pending, and <0 when a IO or other
* error has occurred.
*
* Walks the tree and computes the hashes at each level from the
- * hashes below. This can only be called once per tree creation
- * since it will mark entries verified. Expects dm_bht_populate() to
- * correctly populate the tree from the read_callback_stub.
- *
- * This function should not be used when verifying the same tree and
- * should not be used with multiple simultaneous operators on @bht.
+ * hashes below.
*/
-int dm_bht_compute(struct dm_bht *bht, void *read_cb_ctx)
+int dm_bht_compute(struct dm_bht *bht)
{
int depth, r = 0;
@@ -82,15 +92,7 @@
for (i = 0; i < level->count; i++, entry++) {
unsigned int count = bht->node_count;
- struct page *pg;
- pg = alloc_page(GFP_NOIO);
- if (!pg) {
- DMCRIT("an error occurred while reading entry");
- goto out;
- }
-
- entry->nodes = page_address(pg);
memset(entry->nodes, 0, PAGE_SIZE);
atomic_set(&entry->state, DM_BHT_ENTRY_READY);
@@ -122,126 +124,25 @@
}
/**
- * dm_bht_sync - writes the tree in memory to disk
- * @bht: pointer to a dm_bht_create()d bht
- * @write_ctx: callback context for writes issued
- *
- * Since all entry nodes are PAGE_SIZE, the data will be pre-aligned and
- * padded.
- */
-int dm_bht_sync(struct dm_bht *bht, void *write_cb_ctx)
-{
- int depth;
- int ret = 0;
- int state;
- sector_t sector;
- struct dm_bht_level *level;
- struct dm_bht_entry *entry;
- struct dm_bht_entry *entry_end;
-
- for (depth = 0; depth < bht->depth; ++depth) {
- level = dm_bht_get_level(bht, depth);
- entry_end = level->entries + level->count;
- sector = level->sector;
- for (entry = level->entries; entry < entry_end; ++entry) {
- state = atomic_read(&entry->state);
- if (state <= DM_BHT_ENTRY_PENDING) {
- DMERR("At depth %d, entry %lu is not ready",
- depth,
- (unsigned long)(entry - level->entries));
- return state;
- }
- ret = bht->write_cb(write_cb_ctx,
- sector,
- entry->nodes,
- to_sector(PAGE_SIZE),
- entry);
- if (ret) {
- DMCRIT("an error occurred writing entry %lu",
- (unsigned long)(entry - level->entries));
- return ret;
- }
- sector += to_sector(PAGE_SIZE);
- }
- }
-
- return 0;
-}
-
-/**
* dm_bht_store_block - sets a given block's hash in the tree
* @bht: pointer to a dm_bht_create()d bht
* @block: numeric index of the block in the tree
- * @digest: array of u8s containing the digest of length @bht->digest_size
+ * @block_data: array of u8s containing the block of data to hash
*
- * Returns 0 on success, >0 when data is pending, and <0 when a IO or other
- * error has occurred.
+ * Returns 0 on success.
*
* If the containing entry in the tree is unallocated, it will allocate memory
- * and mark the entry as ready. All other block entries will be 0s. This
- * function is not safe for simultaneous use when verifying data and should not
- * be used if the @bht is being accessed by any other functions in any other
- * threads/processes.
+ * and mark the entry as ready. All other block entries will be 0s.
*
- * It is expected that virt_to_page will work on |block_data|.
+ * It is up to the users of the update interface to ensure the entry data is
+ * fully populated prior to use. The number of updated entries is NOT tracked.
*/
int dm_bht_store_block(struct dm_bht *bht, unsigned int block,
u8 *block_data)
{
- int depth;
- unsigned int index;
- unsigned int node_index;
- struct dm_bht_entry *entry;
- struct dm_bht_level *level;
- int state;
- struct page *node_page = NULL;
+ int depth = bht->depth;
+ struct dm_bht_entry *entry = dm_bht_get_entry(bht, depth - 1, block);
+ u8 *node = dm_bht_get_node(bht, entry, depth, block);
- /* Look at the last level of nodes above the leaves (data blocks) */
- depth = bht->depth - 1;
-
- /* Index into the level */
- level = dm_bht_get_level(bht, depth);
- index = dm_bht_index_at_level(bht, depth, block);
- /* Grab the node index into the current entry by getting the
- * index at the leaf-level.
- */
- node_index = dm_bht_index_at_level(bht, depth + 1, block) %
- bht->node_count;
- entry = &level->entries[index];
-
- DMDEBUG("Storing block %u in d=%d,ei=%u,ni=%u,s=%d",
- block, depth, index, node_index,
- atomic_read(&entry->state));
-
- state = atomic_cmpxchg(&entry->state,
- DM_BHT_ENTRY_UNALLOCATED,
- DM_BHT_ENTRY_PENDING);
- /* !!! Note. It is up to the users of the update interface to
- * ensure the entry data is fully populated prior to use.
- * The number of updated entries is NOT tracked.
- */
- if (state == DM_BHT_ENTRY_UNALLOCATED) {
- node_page = alloc_page(GFP_KERNEL);
- if (!node_page) {
- atomic_set(&entry->state, DM_BHT_ENTRY_ERROR);
- return -ENOMEM;
- }
- entry->nodes = page_address(node_page);
- memset(entry->nodes, 0, PAGE_SIZE);
- /* TODO(wad) could expose this to the caller to that they
- * can transition from unallocated to ready manually.
- */
- atomic_set(&entry->state, DM_BHT_ENTRY_READY);
- } else if (state <= DM_BHT_ENTRY_ERROR) {
- DMCRIT("leaf entry for block %u is invalid",
- block);
- return state;
- } else if (state == DM_BHT_ENTRY_PENDING) {
- DMERR("leaf data is pending for block %u", block);
- return 1;
- }
-
- dm_bht_compute_hash(bht, virt_to_page(block_data), 0,
- dm_bht_node(bht, entry, node_index));
- return 0;
+ return dm_bht_compute_hash(bht, virt_to_page(block_data), 0, node);
}
diff --git a/dm-bht.h b/dm-bht.h
index e34b101..2387c66 100644
--- a/dm-bht.h
+++ b/dm-bht.h
@@ -135,8 +135,8 @@
* should not be directly used for verification. (It should be repopulated.)
* In addition, these functions aren't meant to be called in parallel.
*/
-int dm_bht_compute(struct dm_bht *bht, void *read_cb_ctx);
-int dm_bht_sync(struct dm_bht *bht, void *write_cb_ctx);
+int dm_bht_compute(struct dm_bht *bht);
+void dm_bht_set_buffer(struct dm_bht *bht, void *buffer);
int dm_bht_store_block(struct dm_bht *bht, unsigned int block,
u8 *block_data);
int dm_bht_zeroread_callback(void *ctx, sector_t start, u8 *dst, sector_t count,
diff --git a/dm-bht_unittest.cc b/dm-bht_unittest.cc
index 59d22d2..3871a38 100644
--- a/dm-bht_unittest.cc
+++ b/dm-bht_unittest.cc
@@ -38,19 +38,34 @@
// Simple test to help valgrind/tcmalloc catch bad mem management
TEST(DmBht, CreateZeroPopulateDestroy) {
struct dm_bht bht;
+ sector_t sectors;
// This should fail.
- unsigned int blocks = 16384;
+ unsigned int blocks, total_blocks = 16384;
u8 *data = (u8 *)my_memalign(PAGE_SIZE, PAGE_SIZE);
+ void * hash_data;
+
+ blocks = total_blocks;
// Store all the block hashes of blocks of 0.
memset(reinterpret_cast<void *>(data), 0, sizeof(data));
EXPECT_EQ(0, dm_bht_create(&bht, blocks, "sha256"));
dm_bht_set_read_cb(&bht, dm_bht_zeroread_callback);
+ sectors = dm_bht_sectors(&bht);
+ hash_data = new u8[to_bytes(sectors)];
+ dm_bht_set_buffer(&bht, hash_data);
+
do {
EXPECT_EQ(dm_bht_store_block(&bht, blocks - 1, data), 0);
} while (--blocks > 0);
- EXPECT_EQ(0, dm_bht_compute(&bht, NULL));
+ // Load the tree from the pre-populated hash data
+ for (blocks = 0; blocks < total_blocks; blocks += bht.node_count)
+ EXPECT_GE(dm_bht_populate(&bht,
+ reinterpret_cast<void *>(this),
+ blocks),
+ 0);
+ EXPECT_EQ(0, dm_bht_compute(&bht));
EXPECT_EQ(0, dm_bht_destroy(&bht));
+ free(hash_data);
free(data);
}
@@ -59,14 +74,6 @@
void SetUp() {
}
- int Write(sector_t start, u8 *src, sector_t count) {
- EXPECT_LT(start, sectors_);
- EXPECT_EQ(to_bytes(count), PAGE_SIZE);
- u8 *dst = &hash_data_[to_bytes(start)];
- memcpy(dst, src, to_bytes(count));
- return 0;
- }
-
int Read(sector_t start, u8 *dst, sector_t count) {
EXPECT_LT(start, sectors_);
EXPECT_EQ(to_bytes(count), PAGE_SIZE);
@@ -75,17 +82,6 @@
return 0;
}
- static int WriteCallback(void *mbht_instance,
- sector_t start,
- u8 *src,
- sector_t count,
- struct dm_bht_entry *entry) {
- MemoryBhtTest *mbht = reinterpret_cast<MemoryBhtTest *>(mbht_instance);
- mbht->Write(start, src, count);
- dm_bht_write_completed(entry, 0);
- return 0;
- }
-
static int ReadCallback(void *mbht_instance,
sector_t start,
u8 *dst,
@@ -99,52 +95,57 @@
protected:
// Creates a new dm_bht and sets it in the existing MemoryBht.
- void NewBht(const unsigned int total_blocks,
- const char *digest_algorithm,
- const char *salt) {
- bht_.reset(new dm_bht());
- EXPECT_EQ(0, dm_bht_create(bht_.get(), total_blocks, digest_algorithm));
- if (hash_data_.get() == NULL) {
- sectors_ = dm_bht_sectors(bht_.get());
- hash_data_.reset(new u8[to_bytes(sectors_)]);
- }
- dm_bht_set_write_cb(bht_.get(), MemoryBhtTest::WriteCallback);
- dm_bht_set_read_cb(bht_.get(), MemoryBhtTest::ReadCallback);
- if (salt)
- dm_bht_set_salt(bht_.get(), salt);
- }
- void SetupBht(const unsigned int total_blocks,
- const char *digest_algorithm,
- const char *salt) {
- NewBht(total_blocks, digest_algorithm, salt);
-
+ void SetupHash(const unsigned int total_blocks,
+ const char *digest_algorithm,
+ const char *salt,
+ void *hash_data) {
+ struct dm_bht bht;
u8 *data = (u8 *)my_memalign(PAGE_SIZE, PAGE_SIZE);
memset(data, 0, PAGE_SIZE);
+ EXPECT_EQ(0, dm_bht_create(&bht, total_blocks, digest_algorithm));
+ if (salt)
+ dm_bht_set_salt(&bht, salt);
+ dm_bht_set_buffer(&bht, hash_data);
+
unsigned int blocks = total_blocks;
do {
- EXPECT_EQ(dm_bht_store_block(bht_.get(), blocks - 1, data), 0);
+ EXPECT_EQ(dm_bht_store_block(&bht, blocks - 1, data), 0);
} while (--blocks > 0);
- dm_bht_set_read_cb(bht_.get(), dm_bht_zeroread_callback);
- EXPECT_EQ(0, dm_bht_compute(bht_.get(), NULL));
- EXPECT_EQ(0, dm_bht_sync(bht_.get(), reinterpret_cast<void *>(this)));
- u8 digest[1024];
- dm_bht_root_hexdigest(bht_.get(), digest, sizeof(digest));
- LOG(INFO) << "MemoryBhtTest root is " << digest;
- EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
- // bht is now dead and mbht_ is a prepared hash image
+ EXPECT_EQ(0, dm_bht_compute(&bht));
- NewBht(total_blocks, digest_algorithm, salt);
+ u8 digest[1024];
+ dm_bht_root_hexdigest(&bht, digest, sizeof(digest));
+ LOG(INFO) << "MemoryBhtTest root is " << digest;
+
+ free(data);
+ }
+ void SetupBht(const unsigned int total_blocks,
+ const char *digest_algorithm,
+ const char *salt) {
+ bht_.reset(new dm_bht());
+
+ EXPECT_EQ(0, dm_bht_create(bht_.get(), total_blocks, digest_algorithm));
+ if (hash_data_.get() == NULL) {
+ sectors_ = dm_bht_sectors(bht_.get());
+ hash_data_.reset(new u8[to_bytes(sectors_)]);
+ }
+
+ if (salt)
+ dm_bht_set_salt(bht_.get(), salt);
+
+ SetupHash(total_blocks, digest_algorithm, salt, &hash_data_[0]);
+ dm_bht_set_read_cb(bht_.get(), MemoryBhtTest::ReadCallback);
// Load the tree from the pre-populated hash data
+ unsigned int blocks;
for (blocks = 0; blocks < total_blocks; blocks += bht_->node_count)
EXPECT_GE(dm_bht_populate(bht_.get(),
reinterpret_cast<void *>(this),
blocks),
0);
- free(data);
}
scoped_ptr<struct dm_bht> bht_;
diff --git a/file_hasher.cc b/file_hasher.cc
index e3b9edd..c9bda99 100644
--- a/file_hasher.cc
+++ b/file_hasher.cc
@@ -78,15 +78,19 @@
LOG(ERROR) << "Could not create the BH tree";
return false;
}
+
+ sectors_ = dm_bht_sectors(&tree_);
+ hash_data_ = new u8[to_bytes(sectors_)];
+
dm_bht_set_write_cb(&tree_, FileHasher::WriteCallback);
// No reading is needed.
dm_bht_set_read_cb(&tree_, dm_bht_zeroread_callback);
-
+ dm_bht_set_buffer(&tree_, hash_data_);
return true;
}
bool FileHasher::Store() {
- return !dm_bht_sync(&tree_, reinterpret_cast<void *>(destination_));
+ return destination_->WriteAt(to_bytes(sectors_), hash_data_, 0);
}
bool FileHasher::Hash() {
@@ -105,7 +109,7 @@
}
++block;
}
- return !dm_bht_compute(&tree_, reinterpret_cast<void *>(destination_));
+ return !dm_bht_compute(&tree_);
}
void FileHasher::PrintTable(bool colocated) {
diff --git a/file_hasher.h b/file_hasher.h
index 142be69..007c434 100644
--- a/file_hasher.h
+++ b/file_hasher.h
@@ -25,7 +25,6 @@
block_limit_(0),
alg_(NULL) { }
// TODO(wad) add initialized_ variable to check.
- virtual ~FileHasher() { dm_bht_destroy(&tree_); }
virtual bool Initialize(simple_file::File *source,
simple_file::File *destination,
unsigned int blocks,
@@ -52,7 +51,9 @@
unsigned int block_limit_;
const char *alg_;
const char *salt_;
+ u8 *hash_data_;
struct dm_bht tree_;
+ sector_t sectors_;
};
} // namespace verity