storage: Remove incorrect assert

write_current_super_block can be called on a fs with a failed
initial_super_block_tr from fs_unknown_super_block_state_all (so
reinitialize will be false) if:

1. transaction_initial_super_block_complete is called to complete the
   initial_super_block_tr
2. One of the block writes for initial_super_block_tr's blocks fails
   with BLOCK_WRITE_FAILED_UNKNOWN_STATE

The block write failure will fail the initial_super_block_tr, then the
UNKNOWN_STATE will cause a call to fs_unknown_super_block_state_all,
which then calls write_current_super_block(initial_super_block_tr, false).

Test: storage_host_test
Bug: 400931440
Change-Id: I538f71ab3c91f650737552c6c9563f32c99c0142
diff --git a/super.c b/super.c
index 0dba82e..3ade808 100644
--- a/super.c
+++ b/super.c
@@ -370,17 +370,7 @@
          * only allow transaction_initial_super_block_complete() to reinitialize
          * a failed special transaction after it attempts and fails to write the
          * block to disk.
-         *
-         * Since we pin special superblock entries in the block cache and
-         * therefore cannot evict them with normal transactions,
-         * transaction_initial_super_block_complete() is the only place we can
-         * attempt a special transaction write, and if it fails the transaction
-         * is immediately reinitialized. Therefore we should only ever be in a
-         * failed state if reinitialize is true (i.e. we are being called from
-         * transaction_initial_super_block_complete()).
          */
-
-        assert(reinitialize || !fs->initial_super_block_tr->failed);
         if (!fs->initial_super_block_tr->failed || !reinitialize) {
             return;
         }
diff --git a/test/storage_host_test/storage_host_test.c b/test/storage_host_test/storage_host_test.c
index 4d18beb..74aac9a 100644
--- a/test/storage_host_test/storage_host_test.c
+++ b/test/storage_host_test/storage_host_test.c
@@ -705,6 +705,61 @@
 test_abort:;
 }
 
+TEST_P(StorageTest, FailedSpecialTransactionWithCommitWrites) {
+    /* Create a transaction with some changes. Make RPMB writes fail. */
+    fail_next_rpmb_writes(1, true);
+    file_test(&_state->tr, __func__, FILE_OPEN_CREATE_EXCLUSIVE, 1, 0, 0, false,
+              0);
+
+    /* Try to commit the transaction while RPMB writes are failing.
+     * The failed RPMB write leaves the RPMB in unknown state (b/c the rpmb
+     * device has commit_failed_writes set), so an initial_super_block_tr is
+     * created for this filesystem. */
+    transaction_complete(&_state->tr);
+    ASSERT_EQ(true, _state->tr.failed);
+    ASSERT_NE(NULL, _state->tr.fs->initial_super_block_tr);
+    ASSERT_EQ(false, _state->tr.fs->initial_super_block_tr->failed);
+    ASSERT_NE(_state->tr.fs->super_block_version,
+              _state->tr.fs->written_super_block_version);
+    expect_errors(TRUSTY_STORAGE_ERROR_RPMB_COUNTER_MISMATCH_RECOVERED, 1);
+
+    /* Reactivate transaction. RPMB writes are still broken. */
+    transaction_activate(&_state->tr);
+    fail_next_rpmb_writes(1, true);
+    file_test(&_state->tr, __func__, FILE_OPEN_CREATE_EXCLUSIVE, 1, 0, 0, false,
+              0);
+
+    /* initial_super_block_tr exists, so it has to be committed before the
+     * current transaction. That commit fails because its RPMB write fails,
+     * leaving the filesystem in unknown state (again b/c the rpmb device has
+     * commit_failed_writes set). */
+    block_cache_clean_transaction(&_state->tr);
+    ASSERT_EQ(true, _state->tr.failed);
+    ASSERT_NE(NULL, _state->tr.fs->initial_super_block_tr);
+    /* initial_super_block_tr failed, but
+     * transaction_initial_super_block_complete reinitializes it. */
+    EXPECT_EQ(false, _state->tr.fs->initial_super_block_tr->failed);
+
+    /* Reactivate transaction again. RPMB writes work now. */
+    transaction_activate(&_state->tr);
+    file_test(&_state->tr, __func__, FILE_OPEN_CREATE_EXCLUSIVE, 1, 0, 0, false,
+              0);
+
+    /* initial_super_block_tr exists, so it has to be committed before the
+     * current transaction. Both transactions succeed. */
+    block_cache_clean_transaction(&_state->tr);
+    ASSERT_EQ(false, _state->tr.failed);
+    EXPECT_EQ(NULL, _state->tr.fs->initial_super_block_tr);
+    transaction_complete(&_state->tr);
+    ASSERT_EQ(false, _state->tr.failed);
+    ASSERT_EQ(NULL, _state->tr.fs->initial_super_block_tr);
+
+test_abort:;
+    if (!_state->tr.failed) {
+        transaction_fail(&_state->tr);
+    }
+}
+
 TEST(StorageTest, FlushFailingSpecialTransaction) {
     struct transaction td_tr;
     struct transaction tp_tr;