Browse Source

recovery: Fork a process for fuse when sideloading from SD card.

For applying update from SD card, we used to use a thread to serve the
file with fuse. Since accessing through fuse involves going from kernel
to userspace to kernel, it may run into deadlock (e.g. for mmap_sem)
when a page fault occurs. Switch to using a process instead.

Bug: 23783099
Bug: 26313124
Change-Id: Iac0f55b1bdb078cadb520cfe1133e70fbb26eadd
Tao Bao 5 years ago
parent
commit
cdcf28f54f
3 changed files with 69 additions and 69 deletions
  1. 11
    63
      fuse_sdcard_provider.cpp
  2. 1
    2
      fuse_sdcard_provider.h
  3. 57
    4
      recovery.cpp

+ 11
- 63
fuse_sdcard_provider.cpp View File

@@ -18,7 +18,6 @@
18 18
 #include <stdio.h>
19 19
 #include <string.h>
20 20
 #include <errno.h>
21
-#include <pthread.h>
22 21
 #include <sys/mount.h>
23 22
 #include <sys/stat.h>
24 23
 #include <unistd.h>
@@ -60,81 +59,30 @@ static void close_file(void* cookie) {
60 59
     close(fd->fd);
61 60
 }
62 61
 
63
-struct token {
64
-    pthread_t th;
65
-    const char* path;
66
-    int result;
67
-};
68
-
69
-static void* run_sdcard_fuse(void* cookie) {
70
-    token* t = reinterpret_cast<token*>(cookie);
71
-
62
+bool start_sdcard_fuse(const char* path) {
72 63
     struct stat sb;
73
-    if (stat(t->path, &sb) < 0) {
74
-        fprintf(stderr, "failed to stat %s: %s\n", t->path, strerror(errno));
75
-        t->result = -1;
76
-        return NULL;
64
+    if (stat(path, &sb) == -1) {
65
+        fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
66
+        return false;
77 67
     }
78 68
 
79
-    struct file_data fd;
80
-    struct provider_vtab vtab;
81
-
82
-    fd.fd = open(t->path, O_RDONLY);
83
-    if (fd.fd < 0) {
84
-        fprintf(stderr, "failed to open %s: %s\n", t->path, strerror(errno));
85
-        t->result = -1;
86
-        return NULL;
69
+    file_data fd;
70
+    fd.fd = open(path, O_RDONLY);
71
+    if (fd.fd == -1) {
72
+        fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
73
+        return false;
87 74
     }
88 75
     fd.file_size = sb.st_size;
89 76
     fd.block_size = 65536;
90 77
 
78
+    provider_vtab vtab;
91 79
     vtab.read_block = read_block_file;
92 80
     vtab.close = close_file;
93 81
 
94
-    t->result = run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size);
95
-    return NULL;
96
-}
97
-
98
-// How long (in seconds) we wait for the fuse-provided package file to
99
-// appear, before timing out.
100
-#define SDCARD_INSTALL_TIMEOUT 10
101
-
102
-void* start_sdcard_fuse(const char* path) {
103
-    token* t = new token;
104
-
105
-    t->path = path;
106
-    pthread_create(&(t->th), NULL, run_sdcard_fuse, t);
107
-
108
-    struct stat st;
109
-    int i;
110
-    for (i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
111
-        if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
112
-            if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
113
-                sleep(1);
114
-                continue;
115
-            } else {
116
-                return NULL;
117
-            }
118
-        }
119
-    }
120
-
121 82
     // The installation process expects to find the sdcard unmounted.
122 83
     // Unmount it with MNT_DETACH so that our open file continues to
123 84
     // work but new references see it as unmounted.
124 85
     umount2("/sdcard", MNT_DETACH);
125 86
 
126
-    return t;
127
-}
128
-
129
-void finish_sdcard_fuse(void* cookie) {
130
-    if (cookie == NULL) return;
131
-    token* t = reinterpret_cast<token*>(cookie);
132
-
133
-    // Calling stat() on this magic filename signals the fuse
134
-    // filesystem to shut down.
135
-    struct stat st;
136
-    stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
137
-
138
-    pthread_join(t->th, NULL);
139
-    delete t;
87
+    return run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size) == 0;
140 88
 }

+ 1
- 2
fuse_sdcard_provider.h View File

@@ -17,7 +17,6 @@
17 17
 #ifndef __FUSE_SDCARD_PROVIDER_H
18 18
 #define __FUSE_SDCARD_PROVIDER_H
19 19
 
20
-void* start_sdcard_fuse(const char* path);
21
-void finish_sdcard_fuse(void* token);
20
+bool start_sdcard_fuse(const char* path);
22 21
 
23 22
 #endif

+ 57
- 4
recovery.cpp View File

@@ -28,6 +28,7 @@
28 28
 #include <sys/klog.h>
29 29
 #include <sys/stat.h>
30 30
 #include <sys/types.h>
31
+#include <sys/wait.h>
31 32
 #include <time.h>
32 33
 #include <unistd.h>
33 34
 
@@ -833,6 +834,10 @@ static void choose_recovery_file(Device* device) {
833 834
     }
834 835
 }
835 836
 
837
+// How long (in seconds) we wait for the fuse-provided package file to
838
+// appear, before timing out.
839
+#define SDCARD_INSTALL_TIMEOUT 10
840
+
836 841
 static int apply_from_sdcard(Device* device, bool* wipe_cache) {
837 842
     modified_flash = true;
838 843
 
@@ -850,14 +855,62 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) {
850 855
 
851 856
     ui->Print("\n-- Install %s ...\n", path);
852 857
     set_sdcard_update_bootloader_message();
853
-    void* token = start_sdcard_fuse(path);
854 858
 
855
-    int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
859
+    // We used to use fuse in a thread as opposed to a process. Since accessing
860
+    // through fuse involves going from kernel to userspace to kernel, it leads
861
+    // to deadlock when a page fault occurs. (Bug: 26313124)
862
+    pid_t child;
863
+    if ((child = fork()) == 0) {
864
+        bool status = start_sdcard_fuse(path);
865
+
866
+        _exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
867
+    }
868
+
869
+    // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the fuse in child
870
+    // process is ready.
871
+    int result = INSTALL_ERROR;
872
+    int status;
873
+    bool waited = false;
874
+    for (int i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
875
+        if (waitpid(child, &status, WNOHANG) == -1) {
876
+            result = INSTALL_ERROR;
877
+            waited = true;
878
+            break;
879
+        }
880
+
881
+        struct stat sb;
882
+        if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &sb) == -1) {
883
+            if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
884
+                sleep(1);
885
+                continue;
886
+            } else {
887
+                LOGE("Timed out waiting for the fuse-provided package.\n");
888
+                result = INSTALL_ERROR;
889
+                kill(child, SIGKILL);
890
+                break;
891
+            }
892
+        }
893
+
894
+        result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
856 895
                                  TEMPORARY_INSTALL_FILE, false);
896
+        break;
897
+    }
898
+
899
+    if (!waited) {
900
+        // Calling stat() on this magic filename signals the fuse
901
+        // filesystem to shut down.
902
+        struct stat sb;
903
+        stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &sb);
904
+
905
+        waitpid(child, &status, 0);
906
+    }
907
+
908
+    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
909
+        LOGE("Error exit from the fuse process: %d\n", WEXITSTATUS(status));
910
+    }
857 911
 
858
-    finish_sdcard_fuse(token);
859 912
     ensure_path_unmounted(SDCARD_ROOT);
860
-    return status;
913
+    return result;
861 914
 }
862 915
 
863 916
 // Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER.  Returning NO_ACTION