verity: create a regular trie when depth=0

We want to eventually remove support for the depth constructor parameter
only create trees where level[0]->count = 1.

BUG=9752
TEST=Ran dm-verity.git unit tests. Ran platform_DMVerityCorruption on H/W.

Change-Id: Ie05ebc93a9c52055b4573ccd8811acbbb114adf3

R=wad@chromium.org,taysom@chromium.org,ups@chromium.org

Review URL: http://codereview.chromium.org/6670096
diff --git a/dm-bht.c b/dm-bht.c
index 5957cb7..1665c74 100644
--- a/dm-bht.c
+++ b/dm-bht.c
@@ -265,27 +265,6 @@
 		goto bad_block_count;
 	}
 
-	bht->depth = depth;  /* assignment below */
-	DMDEBUG("Setting depth %u", depth);
-	if (!depth || depth > UINT_MAX / sizeof(struct dm_bht_level)) {
-		DMERR("bht depth is invalid: %u", depth);
-		status = -EINVAL;
-		goto bad_depth;
-	}
-
-	/* Allocate levels. Each level of the tree may have an arbitrary number
-	 * of dm_bht_entry structs.  Each entry contains node_count nodes.
-	 * Each node in the tree is a cryptographic digest of either node_count
-	 * nodes on the subsequent level or of a specific block on disk.
-	 */
-	bht->levels = (struct dm_bht_level *)
-			kcalloc(depth, sizeof(struct dm_bht_level), GFP_KERNEL);
-	if (!bht->levels) {
-		DMERR("failed to allocate tree levels");
-		status = -ENOMEM;
-		goto bad_level_alloc;
-	}
-
 	/* Each dm_bht_entry->nodes is one page.  The node code tracks
 	 * how many nodes fit into one entry where a node is a single
 	 * hash (message digest).
@@ -302,6 +281,19 @@
 		status = -EINVAL;
 		goto bad_node_count;
 	}
+
+	/* if depth == 0, create a "regular" trie with a single root block */
+	if (depth == 0)
+		depth = DIV_ROUND_UP(fls(block_count - 1),
+				     bht->node_count_shift);
+	if (depth > UINT_MAX / sizeof(struct dm_bht_level)) {
+		DMERR("bht depth is invalid: %u", depth);
+		status = -EINVAL;
+		goto bad_depth;
+	}
+	DMDEBUG("Setting depth to %u.", depth);
+	bht->depth = depth;
+
 	/* Ensure that we can safely shift by this value. */
 	if (depth * bht->node_count_shift >= sizeof(unsigned int) * 8) {
 		DMERR("specified depth and node_count_shift is too large");
@@ -309,6 +301,19 @@
 		goto bad_node_count;
 	}
 
+	/* Allocate levels. Each level of the tree may have an arbitrary number
+	 * of dm_bht_entry structs.  Each entry contains node_count nodes.
+	 * Each node in the tree is a cryptographic digest of either node_count
+	 * nodes on the subsequent level or of a specific block on disk.
+	 */
+	bht->levels = (struct dm_bht_level *)
+			kcalloc(depth, sizeof(struct dm_bht_level), GFP_KERNEL);
+	if (!bht->levels) {
+		DMERR("failed to allocate tree levels");
+		status = -ENOMEM;
+		goto bad_level_alloc;
+	}
+
 	/* Setup callback stubs */
 	bht->read_cb = &dm_bht_read_callback_stub;
 	bht->write_cb = &dm_bht_write_callback_stub;
@@ -322,8 +327,8 @@
 bad_entries_alloc:
 	while (bht->depth-- > 0)
 		kfree(bht->levels[bht->depth].entries);
-bad_node_count:
 	kfree(bht->levels);
+bad_node_count:
 bad_level_alloc:
 bad_block_count:
 bad_depth:
diff --git a/dm-bht_unittest.cc b/dm-bht_unittest.cc
index 2eb2297..8976418 100644
--- a/dm-bht_unittest.cc
+++ b/dm-bht_unittest.cc
@@ -206,6 +206,29 @@
   free(zero_page);
 }
 
+TEST_F(MemoryBhtTest, CreateThenVerifyZeroDepth) {
+  static const unsigned int total_blocks = 16384;
+  // Set the root hash for a 0-filled image
+  static const char kRootDigest[] =
+    "45d65d6f9e5a962f4d80b5f1bd7a918152251c27bdad8c5f52b590c129833372";
+  // A page of all zeros
+  u8 *zero_page = (u8 *)my_memalign(PAGE_SIZE, PAGE_SIZE);
+
+  memset(zero_page, 0, PAGE_SIZE);
+
+  SetupBht(0, total_blocks, "sha256");
+  dm_bht_set_root_hexdigest(bht_.get(),
+                            reinterpret_cast<const u8 *>(kRootDigest));
+
+  for (unsigned int blocks = 0; blocks < total_blocks; ++blocks) {
+    DLOG(INFO) << "verifying block: " << blocks;
+    EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, zero_page));
+  }
+
+  EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
+  free(zero_page);
+}
+
 TEST_F(MemoryBhtTest, CreateThenVerifyRealParameters) {
   static const unsigned int total_blocks = 217600;
   // Set the root hash for a 0-filled image
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index dd617bd..0a7e322 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -15,6 +15,8 @@
 #define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
 #define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
 
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
 #define sector_div(n, b) ({ \
 	int _res; \
 	_res = (n) % (b); \