Merge "storageproxyd: Sync parent dir when creating a file"
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index d74a708..c00c399 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -41,11 +41,9 @@
     SS_DIRTY =  1,
 };
 
-static int ssdir_fd = -1;
 static const char *ssdir_name;
 
 static enum sync_state fs_state;
-static enum sync_state dir_state;
 static enum sync_state fd_state[FD_TBL_SIZE];
 
 static bool alternate_mode;
@@ -59,10 +57,6 @@
 {
     uint32_t handle = fd;
 
-    if (open_flags & O_CREAT) {
-        dir_state = SS_DIRTY;
-    }
-
     if (handle < FD_TBL_SIZE) {
             fd_state[fd] = SS_CLEAN; /* fd clean */
             if (open_flags & O_TRUNC) {
@@ -193,7 +187,6 @@
         goto err_response;
     }
 
-    dir_state = SS_DIRTY;
     rc = unlink(path);
     if (rc < 0) {
         rc = errno;
@@ -217,12 +210,21 @@
     return ipc_respond(msg, NULL, 0);
 }
 
+static void sync_parent(const char* path) {
+    int parent_fd;
+    char* parent_path = dirname(path);
+    parent_fd = TEMP_FAILURE_RETRY(open(parent_path, O_RDONLY));
+    if (parent_fd >= 0) {
+        fsync(parent_fd);
+        close(parent_fd);
+    } else {
+        ALOGE("%s: failed to open parent directory \"%s\" for sync: %s\n", __func__, parent_path,
+              strerror(errno));
+    }
+}
 
-int storage_file_open(struct storage_msg *msg,
-                      const void *r, size_t req_len)
-{
-    char *path = NULL;
-    char* parent_path;
+int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len) {
+    char* path = NULL;
     const struct storage_file_open_req *req = r;
     struct storage_file_open_resp resp = {0};
 
@@ -271,7 +273,6 @@
     if (req->flags & STORAGE_FILE_OPEN_TRUNCATE)
         open_flags |= O_TRUNC;
 
-    parent_path = dirname(path);
     if (req->flags & STORAGE_FILE_OPEN_CREATE) {
         /*
          * Create the alternate parent dir if needed & allowed.
@@ -281,8 +282,11 @@
          * it has access to the necessary bit of information.
          */
         if (strstr(req->name, ALTERNATE_DATA_DIR) == req->name) {
+            char* parent_path = dirname(path);
             rc = mkdir(parent_path, S_IRWXU);
-            if (rc && errno != EEXIST) {
+            if (rc == 0) {
+                sync_parent(parent_path);
+            } else if (errno != EEXIST) {
                 ALOGE("%s: Could not create parent directory \"%s\": %s\n", __func__, parent_path,
                       strerror(errno));
             }
@@ -320,6 +324,10 @@
         msg->result = translate_errno(rc);
         goto err_response;
     }
+
+    if (open_flags & O_CREAT) {
+        sync_parent(path);
+    }
     free(path);
 
     /* at this point rc contains storage file fd */
@@ -512,16 +520,10 @@
     alternate_mode = is_gsi_running();
 
     fs_state = SS_CLEAN;
-    dir_state = SS_CLEAN;
     for (uint i = 0; i < FD_TBL_SIZE; i++) {
         fd_state[i] = SS_UNUSED;  /* uninstalled */
     }
 
-    ssdir_fd = open(dirname, O_RDONLY);
-    if (ssdir_fd < 0) {
-        ALOGE("failed to open ss root dir \"%s\": %s\n",
-               dirname, strerror(errno));
-    }
     ssdir_name = dirname;
     return 0;
 }
@@ -545,25 +547,16 @@
          }
     }
 
-    /* check if we need to sync the directory */
-    if (dir_state == SS_DIRTY) {
-        if (fs_state == SS_CLEAN) {
-            rc = fsync(ssdir_fd);
-            if (rc < 0) {
-                ALOGE("fsync for ssdir failed: %s\n", strerror(errno));
-                return rc;
-            }
-        }
-        dir_state = SS_CLEAN;  /* set to clean */
-    }
-
-    /* check if we need to sync the whole fs */
+    /* check if we need to sync all filesystems */
     if (fs_state == SS_DIRTY) {
-        rc = syscall(SYS_syncfs, ssdir_fd);
-        if (rc < 0) {
-            ALOGE("syncfs failed: %s\n", strerror(errno));
-            return rc;
-        }
+        /*
+         * We sync all filesystems here because we don't know what filesystem
+         * needs syncing if there happen to be other filesystems symlinked under
+         * the root data directory. This should not happen in the normal case
+         * because our fd table is large enough to handle the few open files we
+         * use.
+         */
+        sync();
         fs_state = SS_CLEAN;
     }