From 959dcf106dc0f09f8f63f23ad58e56e3a738a2ab Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 28 Apr 2020 22:27:10 +0200 Subject: [PATCH 1/3] Mount fusectl filesystem. To allow us to manually abort FUSE filesystems. Bug: 153411204 Test: inspect /sys/fs/fuse/ Change-Id: I150597635d62932aa70ee696b4d978c822e6ea8d --- rootdir/init.rc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 38ba137e7..2d6719468 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -177,6 +177,9 @@ on init mount binder binder /dev/binderfs stats=global chmod 0755 /dev/binderfs + # Mount fusectl + mount fusectl none /sys/fs/fuse/connections + symlink /dev/binderfs/binder /dev/binder symlink /dev/binderfs/hwbinder /dev/hwbinder symlink /dev/binderfs/vndbinder /dev/vndbinder From dd0440f4e5979e022cebb7a788e9228205df091d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 28 May 2020 16:15:55 +0200 Subject: [PATCH 2/3] Abort FUSE filesystem when Zygote restarts. The FUSE filesystem is implemented by a Zygote child. If Zygote dies, all of its children die along with it, including the FUSE daemon. The FUSE filesystem is cleaned up automatically whenever the /dev/fuse file descriptor of the FUSE daemon is closed. However, due to the way the binder driver holds on to the 'struct files' of processes in the kernel, the closing of FDs of all of Zygote's children is serialized. That in turn means that, if a process has a file with dirty pages on FUSE, and that FD is closed *before* the FUSE FD, the FUSE kernel driver will happily issue a request to the FUSE daemon to serve that request. But since the FUSE userspace daemon is already dead, it will never get served. And because the closing of all FDs is serialized, we will never close the FUSE fd to unblock this request. Solve this particular case by manually aborting the FUSE filesystem when Zygote restarts. Because we now explicitly close the FUSE fd, the FUSE filesystem will be cleaned up, all outstanding requests to it will be cancelled, and new ones will be skipped. Bug: 153411204 Test: kill zygote manually Change-Id: I2cb6c1a03cc1a932461ff33558894a428ff35180 --- rootdir/init.zygote32.rc | 1 + rootdir/init.zygote32_64.rc | 1 + rootdir/init.zygote64.rc | 1 + rootdir/init.zygote64_32.rc | 1 + 4 files changed, 4 insertions(+) diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc index 9adbcba2e..e827cf557 100644 --- a/rootdir/init.zygote32.rc +++ b/rootdir/init.zygote32.rc @@ -5,6 +5,7 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system + onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc index f6149c921..fe6dcfa47 100644 --- a/rootdir/init.zygote32_64.rc +++ b/rootdir/init.zygote32_64.rc @@ -5,6 +5,7 @@ service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-s group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system + onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc index 0e69b1695..adc703102 100644 --- a/rootdir/init.zygote64.rc +++ b/rootdir/init.zygote64.rc @@ -5,6 +5,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system + onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc index 3e8016867..70297484a 100644 --- a/rootdir/init.zygote64_32.rc +++ b/rootdir/init.zygote64_32.rc @@ -5,6 +5,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system + onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver From 860ba643930119c2a54b70184f234a5a2b5386e3 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 28 May 2020 16:42:10 +0200 Subject: [PATCH 3/3] Abort FUSE filesystems during shutdown. To ensure we can shutdown cleanly, and don't hang an outstanding requests to a FUSE host daemon that has already exited. Bug: 153411204 Test: inspect logs during shutdown Change-Id: I8e6479bd54dbc1fc85b087617aa6b16be9f15a3b --- init/reboot.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/init/reboot.cpp b/init/reboot.cpp index ffd58a38d..23a07aa64 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -678,9 +678,12 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str // Reap subcontext pids. ReapAnyOutstandingChildren(); - // 3. send volume shutdown to vold + // 3. send volume abort_fuse and volume shutdown to vold Service* vold_service = ServiceList::GetInstance().FindService("vold"); if (vold_service != nullptr && vold_service->IsRunning()) { + // Manually abort FUSE connections, since the FUSE daemon is already dead + // at this point, and unmounting it might hang. + CallVdc("volume", "abort_fuse"); CallVdc("volume", "shutdown"); vold_service->Stop(); } else {