Add checkpoint sync flag for TD superblock writes.

Writes to the TD filesystem must not be committed while an uncommitted
checkpoint is pending for userdata. Adds a flag to TD superblock write
messages telling storageproxyd to not perform the write until it is safe
to do so.

Test: Boot with userdata checkpointed and attempt a TD write
Bug: 194313068
Change-Id: Idaf63f1cb773c144914c7d362f092d6245f2c4af
diff --git a/block_device_tipc.c b/block_device_tipc.c
index b9f5b72..209324c 100644
--- a/block_device_tipc.c
+++ b/block_device_tipc.c
@@ -167,7 +167,7 @@
 
     ret = rpmb_write(dev_rpmb->state->rpmb_state, data,
                      rpmb_block * BLOCK_SIZE_RPMB_BLOCKS,
-                     BLOCK_SIZE_RPMB_BLOCKS, true);
+                     BLOCK_SIZE_RPMB_BLOCKS, true, dev_rpmb->is_userdata);
 
     SS_DBG_IO("%s: block %" PRIu64 ", base %d, rpmb_block %d, ret %d\n",
               __func__, block, dev_rpmb->base, rpmb_block, ret);
@@ -207,7 +207,8 @@
     assert(data_size == BLOCK_SIZE_MAIN);
 
     ret = ns_write_pos(dev_ns->state->ipc_handle, dev_ns->ns_handle,
-                       block * BLOCK_SIZE_MAIN, data, data_size);
+                       block * BLOCK_SIZE_MAIN, data, data_size,
+                       dev_ns->is_userdata);
     SS_DBG_IO("%s: block %" PRIu64 ", ret %d\n", __func__, block, ret);
     block_cache_complete_write(dev, block, ret != BLOCK_SIZE_MAIN);
 }
@@ -219,7 +220,8 @@
 static void block_device_tipc_init_dev_rpmb(struct block_device_rpmb* dev_rpmb,
                                             struct block_device_tipc* state,
                                             uint16_t base,
-                                            uint32_t block_count) {
+                                            uint32_t block_count,
+                                            bool is_userdata) {
     dev_rpmb->dev.start_read = block_device_tipc_rpmb_start_read;
     dev_rpmb->dev.start_write = block_device_tipc_rpmb_start_write;
     dev_rpmb->dev.wait_for_io = block_device_tipc_rpmb_wait_for_io;
@@ -231,10 +233,12 @@
     list_initialize(&dev_rpmb->dev.io_ops);
     dev_rpmb->state = state;
     dev_rpmb->base = base;
+    dev_rpmb->is_userdata = is_userdata;
 }
 
 static void block_device_tipc_init_dev_ns(struct block_device_ns* dev_ns,
-                                          struct block_device_tipc* state) {
+                                          struct block_device_tipc* state,
+                                          bool is_userdata) {
     dev_ns->dev.start_read = block_device_tipc_ns_start_read;
     dev_ns->dev.start_write = block_device_tipc_ns_start_write;
     dev_ns->dev.wait_for_io = block_device_tipc_ns_wait_for_io;
@@ -246,6 +250,7 @@
     list_initialize(&dev_ns->dev.io_ops);
     dev_ns->state = state;
     dev_ns->ns_handle = 0; /* Filled in later */
+    dev_ns->is_userdata = is_userdata;
 }
 
 /**
@@ -316,7 +321,8 @@
     rpmb_set_key(state, &out->rpmb_key);
 
     ret = rpmb_write(state, in->block_data,
-                     rpmb_key_part_base * BLOCK_SIZE_RPMB_BLOCKS, 1, false);
+                     rpmb_key_part_base * BLOCK_SIZE_RPMB_BLOCKS, 1, false,
+                     false);
     if (ret < 0) {
         SS_ERR("%s: rpmb_write failed (%d)\n", __func__, ret);
         return ret;
@@ -449,7 +455,7 @@
     }
 
     block_device_tipc_init_dev_rpmb(&state->dev_rpmb, state, rpmb_part2_base,
-                                    rpmb_block_count - rpmb_part2_base);
+                                    rpmb_block_count - rpmb_part2_base, false);
 
     /* TODO: allow non-rpmb based tamper proof storage */
     ret = fs_init(&state->tr_state_rpmb, fs_key, &state->dev_rpmb.dev,
@@ -474,7 +480,7 @@
         goto err_fs_rpmb_boot_create_port;
     }
 
-    block_device_tipc_init_dev_ns(&state->dev_ns, state);
+    block_device_tipc_init_dev_ns(&state->dev_ns, state, true);
 
     ret = ns_open_file(state->ipc_handle, "0", &state->dev_ns.ns_handle, true);
     if (ret < 0) {
@@ -484,7 +490,7 @@
     }
 
 #if HAS_FS_TDP
-    block_device_tipc_init_dev_ns(&state->dev_ns_tdp, state);
+    block_device_tipc_init_dev_ns(&state->dev_ns_tdp, state, false);
 
     ret = ns_open_file(state->ipc_handle, "persist/0",
                        &state->dev_ns_tdp.ns_handle, true);
@@ -497,7 +503,7 @@
 
     block_device_tipc_init_dev_rpmb(&state->dev_ns_tdp_rpmb, state,
                                     rpmb_part_sb_tdp_base,
-                                    rpmb_part_sb_ns_block_count);
+                                    rpmb_part_sb_ns_block_count, false);
 
     ret = fs_init(&state->tr_state_ns_tdp, fs_key, &state->dev_ns_tdp.dev,
                   &state->dev_ns_tdp_rpmb.dev, false /* Don't allow wiping */);
@@ -531,7 +537,7 @@
     state->fs_ns.tr_state = &state->tr_state_ns;
 
     block_device_tipc_init_dev_rpmb(&state->dev_ns_rpmb, state, rpmb_part1_base,
-                                    rpmb_part_sb_ns_block_count);
+                                    rpmb_part_sb_ns_block_count, true);
 
     ret = fs_init(&state->tr_state_ns, fs_key, &state->dev_ns.dev,
                   &state->dev_ns_rpmb.dev, new_ns_fs);
diff --git a/block_device_tipc.h b/block_device_tipc.h
index 47112fa..c45a16b 100644
--- a/block_device_tipc.h
+++ b/block_device_tipc.h
@@ -28,14 +28,17 @@
 
 /**
  * struct block_device_rpmb
- * @state:      Pointer to shared state containing ipc_handle and rpmb_state
- * @dev:        Block device state
- * @base:       First block to use in rpmb partition
+ * @state:       Pointer to shared state containing ipc_handle and rpmb_state
+ * @dev:         Block device state
+ * @base:        First block to use in rpmb partition
+ * @is_userdata: Is this RPMB device tied to the state of the userdata
+ * partition?
  */
 struct block_device_rpmb {
     struct block_device dev;
     struct block_device_tipc* state;
     uint16_t base;
+    bool is_userdata;
 };
 
 /**
@@ -43,11 +46,14 @@
  * @dev:        Block device state
  * @state:      Pointer to shared state containing ipc_handle
  * @ns_handle:  Handle
+ * @is_userdata: Is the backing file for this device in the (non-persistent)
+ *               userdata partition?
  */
 struct block_device_ns {
     struct block_device dev;
     struct block_device_tipc* state;
     ns_handle_t ns_handle;
+    bool is_userdata;
 };
 
 struct client_port_context {
diff --git a/rpmb.c b/rpmb.c
index 473e26b..f5b1c0f 100644
--- a/rpmb.c
+++ b/rpmb.c
@@ -213,7 +213,7 @@
     memcpy(cmd.key_mac.byte, key->byte, sizeof(cmd.key_mac.byte));
 
     ret = rpmb_send(state->mmc_handle, &cmd, sizeof(cmd), &rescmd,
-                    sizeof(rescmd), &res, sizeof(res), false);
+                    sizeof(rescmd), &res, sizeof(res), false, false);
     if (ret < 0)
         return ret;
 
@@ -241,7 +241,7 @@
     struct rpmb_packet res;
 
     ret = rpmb_send(state->mmc_handle, NULL, 0, &cmd, sizeof(cmd), &res,
-                    sizeof(res), false);
+                    sizeof(res), false, false);
     if (ret < 0)
         return ret;
 
@@ -309,7 +309,7 @@
         return -EINVAL;
 
     ret = rpmb_send(state->mmc_handle, NULL, 0, &cmd, sizeof(cmd), res,
-                    sizeof(res[0]) * count, false);
+                    sizeof(res[0]) * count, false, false);
     if (ret < 0)
         return ret;
 
@@ -387,7 +387,8 @@
                            const char* buf,
                            uint16_t addr,
                            uint16_t count,
-                           bool sync) {
+                           bool sync,
+                           bool sync_checkpoint) {
     int i;
     int ret;
     struct rpmb_key mac;
@@ -416,7 +417,7 @@
     }
 
     ret = rpmb_send(state->mmc_handle, cmd, sizeof(cmd[0]) * count, &rescmd,
-                    sizeof(rescmd), &res, sizeof(res), sync);
+                    sizeof(rescmd), &res, sizeof(res), sync, sync_checkpoint);
     if (ret < 0) {
         fprintf(stderr, "rpmb send failed: %d, result: %hu\n", ret,
                 rpmb_get_u16(res.result));
@@ -514,13 +515,14 @@
                const void* buf,
                uint16_t addr,
                uint16_t count,
-               bool sync) {
+               bool sync,
+               bool sync_checkpoint) {
     int ret;
 
     if (!state)
         return -EINVAL;
 
-    ret = rpmb_write_data(state, buf, addr, count, sync);
+    ret = rpmb_write_data(state, buf, addr, count, sync, sync_checkpoint);
     if (ret < 0)
         return ret;
 
diff --git a/rpmb.h b/rpmb.h
index 21c9f8b..647fe0f 100644
--- a/rpmb.h
+++ b/rpmb.h
@@ -51,7 +51,8 @@
                const void* buf,
                uint16_t addr,
                uint16_t count,
-               bool sync);
+               bool sync,
+               bool sync_checkpoint);
 
 /* needs */
 int rpmb_send(void* mmc_handle,
@@ -61,6 +62,7 @@
               size_t write_buf_size,
               void* read_buf,
               size_t read_buf_size,
-              bool sync);
+              bool sync,
+              bool sync_checkpoint);
 
 #endif
diff --git a/tipc_ns.c b/tipc_ns.c
index 6557560..7ba8d69 100644
--- a/tipc_ns.c
+++ b/tipc_ns.c
@@ -66,7 +66,8 @@
               size_t write_size,
               void* read_buf,
               size_t read_size,
-              bool sync) {
+              bool sync,
+              bool sync_checkpoint) {
     SS_DBG_IO(
             "%s: handle %p, rel_write size %zu, write size %zu, read size %zu\n",
             __func__, handle_, reliable_write_size, write_size, read_size);
@@ -90,6 +91,10 @@
                     write_size,
     };
 
+    if (sync_checkpoint) {
+        msg.flags |= STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT;
+    }
+
     struct iovec rx_iov[] = {
             {.iov_base = &msg, .iov_len = sizeof(msg)},
             {.iov_base = read_buf, .iov_len = read_size},
@@ -242,7 +247,8 @@
                  ns_handle_t handle,
                  ns_off_t pos,
                  const void* data,
-                 int data_size) {
+                 int data_size,
+                 bool is_userdata) {
     SS_DBG_IO("%s: handle %llu, pos %llu, size %d\n", __func__, handle, pos,
               data_size);
 
@@ -253,6 +259,7 @@
 
     struct storage_msg msg = {
             .cmd = STORAGE_FILE_WRITE,
+            .flags = is_userdata ? STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT : 0,
             .size = sizeof(msg) + sizeof(req) + data_size,
     };
 
diff --git a/tipc_ns.h b/tipc_ns.h
index 9851f2e..c1c3f0d 100644
--- a/tipc_ns.h
+++ b/tipc_ns.h
@@ -36,4 +36,5 @@
                  ns_handle_t handle,
                  ns_off_t pos,
                  const void* data,
-                 int data_size);
+                 int data_size,
+                 bool is_userdata);