Merge "Clean up fuse bind mount on parent user when clone profile goes away" into main am: 5caf840c13 am: 179874c480
Original change: https://android-review.googlesource.com/c/platform/system/vold/+/3527326
Change-Id: I1e1f888fee7fcc7fcd47fbdec4a6e82f60c0ef15
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index f1221eb..bef6471 100644
--- a/Android.bp
+++ b/Android.bp
@@ -158,6 +158,12 @@
"model/VolumeBase.cpp",
"model/VolumeEncryption.cpp",
],
+ shared_libs: [
+ "server_configurable_flags",
+ ],
+ static_libs: [
+ "vold_flags_c_lib",
+ ],
product_variables: {
arc: {
exclude_srcs: [
@@ -271,3 +277,15 @@
],
path: "binder",
}
+
+aconfig_declarations {
+ name: "vold_flags",
+ package: "android.vold.flags",
+ srcs: ["aconfig/flags.aconfig"],
+ container: "system",
+}
+
+cc_aconfig_library {
+ name: "vold_flags_c_lib",
+ aconfig_declarations: "vold_flags",
+}
\ No newline at end of file
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index dcf92be..c8dbf77 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,6 +3,3 @@
[Builtin Hooks Options]
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
-
-[Hook Scripts]
-aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "."
diff --git a/Process.cpp b/Process.cpp
index 426a425..0115fb1 100644
--- a/Process.cpp
+++ b/Process.cpp
@@ -46,7 +46,7 @@
namespace android {
namespace vold {
-static bool checkMaps(const std::string& path, const std::string& prefix) {
+static bool checkMaps(const std::string& path, const std::vector<std::string>& prefixes) {
bool found = false;
auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
if (!file) {
@@ -60,9 +60,14 @@
std::string::size_type pos = line.find('/');
if (pos != std::string::npos) {
line = line.substr(pos);
- if (android::base::StartsWith(line, prefix)) {
- LOG(WARNING) << "Found map " << path << " referencing " << line;
- found = true;
+ for (const auto& prefix : prefixes) {
+ if (android::base::StartsWith(line, prefix)) {
+ LOG(WARNING) << "Found map " << path << " referencing " << line;
+ found = true;
+ break;
+ }
+ }
+ if (found) {
break;
}
}
@@ -72,12 +77,14 @@
return found;
}
-static bool checkSymlink(const std::string& path, const std::string& prefix) {
+static bool checkSymlink(const std::string& path, const std::vector<std::string>& prefixes) {
std::string res;
if (android::base::Readlink(path, &res)) {
- if (android::base::StartsWith(res, prefix)) {
- LOG(WARNING) << "Found symlink " << path << " referencing " << res;
- return true;
+ for (const auto& prefix : prefixes) {
+ if (android::base::StartsWith(res, prefix)) {
+ LOG(WARNING) << "Found symlink " << path << " referencing " << res;
+ return true;
+ }
}
}
return false;
@@ -129,7 +136,8 @@
return pids.size();
}
-int KillProcessesWithOpenFiles(const std::string& prefix, int signal, bool killFuseDaemon) {
+int KillProcessesWithOpenFiles(const std::vector<std::string>& prefixes, int signal,
+ bool killFuseDaemon) {
std::unordered_set<pid_t> pids;
auto proc_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/proc"), closedir);
@@ -148,10 +156,10 @@
// Look for references to prefix
bool found = false;
auto path = StringPrintf("/proc/%d", pid);
- found |= checkMaps(path + "/maps", prefix);
- found |= checkSymlink(path + "/cwd", prefix);
- found |= checkSymlink(path + "/root", prefix);
- found |= checkSymlink(path + "/exe", prefix);
+ found |= checkMaps(path + "/maps", prefixes);
+ found |= checkSymlink(path + "/cwd", prefixes);
+ found |= checkSymlink(path + "/root", prefixes);
+ found |= checkSymlink(path + "/exe", prefixes);
auto fd_path = path + "/fd";
auto fd_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(fd_path.c_str()), closedir);
@@ -161,7 +169,7 @@
struct dirent* fd_de;
while ((fd_de = readdir(fd_d.get())) != nullptr) {
if (fd_de->d_type != DT_LNK) continue;
- found |= checkSymlink(fd_path + "/" + fd_de->d_name, prefix);
+ found |= checkSymlink(fd_path + "/" + fd_de->d_name, prefixes);
}
}
@@ -198,5 +206,10 @@
return totalKilledPids;
}
+int KillProcessesWithOpenFiles(const std::string& prefix, int signal, bool killFuseDaemon) {
+ return KillProcessesWithOpenFiles(std::vector<std::string>(1, prefix), signal,
+ killFuseDaemon);
+}
+
} // namespace vold
} // namespace android
diff --git a/Process.h b/Process.h
index f3728b5..8a20d1c 100644
--- a/Process.h
+++ b/Process.h
@@ -20,6 +20,8 @@
namespace android {
namespace vold {
+int KillProcessesWithOpenFiles(const std::vector<std::string>& paths, int signal,
+ bool killFuseDaemon = true);
int KillProcessesWithOpenFiles(const std::string& path, int signal, bool killFuseDaemon = true);
int KillProcessesWithTmpfsMounts(const std::string& path, int signal);
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 93938b6..50bd3da 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -17,9 +17,6 @@
},
{
"name": "CtsScopedStorageRedactUriTest"
- },
- {
- "name": "AdoptableHostTest"
}
],
"hwasan-postsubmit": [
@@ -40,9 +37,6 @@
},
{
"name": "CtsScopedStorageRedactUriTest"
- },
- {
- "name": "AdoptableHostTest"
}
]
}
diff --git a/Utils.cpp b/Utils.cpp
index c4070d1..9ad828c 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -1724,6 +1724,139 @@
return result;
}
+/* returns list of non unmounted paths */
+std::vector<std::string> UnmountFusePaths(const std::vector<std::string>& paths_to_unmount) {
+ std::vector<std::string> non_unmounted_paths;
+ for (const auto& path : paths_to_unmount) {
+ LOG(INFO) << "Unmounting fuse path " << path;
+ const char* cpath = path.c_str();
+ if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
+ rmdir(cpath);
+ continue;
+ }
+ non_unmounted_paths.push_back(path);
+ }
+ return non_unmounted_paths;
+}
+
+/* returns list of non unmounted paths */
+std::vector<std::string> UnmountFusePathsWithSleepAndPolling(
+ const std::vector<std::string>& paths_to_unmount) {
+ std::vector<std::string> non_unmounted_paths = paths_to_unmount;
+
+ int count = 10;
+ while (count-- > 0) {
+ usleep(500 * 1000);
+ non_unmounted_paths = UnmountFusePaths(non_unmounted_paths);
+ if (non_unmounted_paths.empty()) {
+ return non_unmounted_paths;
+ }
+ }
+ return non_unmounted_paths;
+}
+
+/* returns list of non unmounted paths */
+std::vector<std::string> KillProcessesWithFuseOpenFilesAndUnmount(
+ const std::vector<std::string>& paths_to_unmount, const std::string& absolute_upper_path,
+ int signal, bool kill_fuse_daemon, bool force_sleep_if_no_processes_killed) {
+
+ // In addition to killing apps using paths to unmount, we need to kill aps using
+ // the upper path (e.g storage/emulated) As they would prevent unmounting fuse
+ std::vector<std::string> paths_to_kill(paths_to_unmount);
+ paths_to_kill.push_back(absolute_upper_path);
+
+ int total_killed_pids = KillProcessesWithOpenFiles(paths_to_kill, signal, kill_fuse_daemon);
+
+ if (sSleepOnUnmount && (force_sleep_if_no_processes_killed || total_killed_pids)) {
+ return UnmountFusePathsWithSleepAndPolling(paths_to_unmount);
+ }
+ return UnmountFusePaths(paths_to_unmount);
+}
+
+status_t UnmountUserFuseEnhanced(userid_t user_id, const std::string& absolute_lower_path,
+ const std::string& relative_upper_path,
+ const std::string& absolute_upper_path,
+ const std::vector<std::string>& bind_mount_paths) {
+ std::vector<std::string> paths_to_unmount(bind_mount_paths);
+
+ std::string fuse_path(StringPrintf("/mnt/user/%d/%s", user_id, relative_upper_path.c_str()));
+ paths_to_unmount.push_back(fuse_path);
+
+ std::string pass_through_path(
+ StringPrintf("/mnt/pass_through/%d/%s", user_id, relative_upper_path.c_str()));
+ paths_to_unmount.push_back(pass_through_path);
+
+ auto start_time = std::chrono::steady_clock::now();
+ LOG(INFO) << "Unmounting fuse paths";
+
+ // Try unmounting without killing any processes
+ paths_to_unmount = UnmountFusePaths(paths_to_unmount);
+ if (paths_to_unmount.empty()) {
+ return android::OK;
+ }
+
+ // Kill processes except for FuseDaemon holding references to fuse paths with SIGINT
+ // And try to unmount afterwards with sleep and polling mechanism
+ paths_to_unmount = KillProcessesWithFuseOpenFilesAndUnmount(
+ paths_to_unmount, absolute_upper_path, SIGINT, /*kill_fuse_daemon*/ false,
+ /*force_sleep_if_no_processes_killed*/false);
+ if (paths_to_unmount.empty()) {
+ return android::OK;
+ }
+
+ // Kill processes except for FuseDaemon holding references to fuse paths with SIGTERM
+ // And try to unmount afterwards with sleep and polling mechanism
+ paths_to_unmount = KillProcessesWithFuseOpenFilesAndUnmount(
+ paths_to_unmount, absolute_upper_path, SIGTERM, /*kill_fuse_daemon*/ false,
+ /*force_sleep_if_no_processes_killed*/false);
+
+ if (paths_to_unmount.empty()) {
+ return android::OK;
+ }
+
+ auto now = std::chrono::steady_clock::now();
+ auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ bool force_sleep_if_no_process_killed = time_elapsed < std::chrono::milliseconds(5000);
+ // Kill processes except for FuseDaemon holding references to fuse paths with SIGKILL
+ // And try to unmount afterwards with sleep and polling mechanism
+ // intentionally force sleep if sSleepOnUnmount isn't set to false
+ // and if we haven't slept in previous retries so that we give MediaProvider time
+ // to release FDs prior to try killing it in the next step
+ paths_to_unmount = KillProcessesWithFuseOpenFilesAndUnmount(
+ paths_to_unmount, absolute_upper_path, SIGKILL, /*kill_fuse_daemon*/ false,
+ force_sleep_if_no_process_killed);
+
+ if (paths_to_unmount.empty()) {
+ return android::OK;
+ }
+
+ // Kill processes including FuseDaemon holding references to fuse paths with SIGKILL
+ // And try to unmount afterwards with sleep and polling mechanism
+ paths_to_unmount = KillProcessesWithFuseOpenFilesAndUnmount(
+ paths_to_unmount, absolute_upper_path, SIGKILL, /*kill_fuse_daemon*/ true,
+ /*force_sleep_if_no_processes_killed*/false);
+ if (paths_to_unmount.empty()) {
+ return android::OK;
+ }
+
+ // If we reached here, then it means that previous kill and unmount retries didn't succeed
+ // Try to unmount with MNT_DETACH so we try lazily unmount
+ android::status_t result = android::OK;
+ for (const auto& path : paths_to_unmount) {
+ LOG(ERROR) << "Failed to unmount. Trying MNT_DETACH " << path;
+ const char* cpath = path.c_str();
+ if (!umount2(cpath, UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL || errno == ENOENT) {
+ rmdir(cpath);
+ continue;
+ }
+ PLOG(ERROR) << "Failed to unmount with MNT_DETACH " << path;
+ if (path == fuse_path) {
+ result = -errno;
+ }
+ }
+ return result;
+}
+
status_t PrepareAndroidDirs(const std::string& volumeRoot) {
std::string androidDir = volumeRoot + kAndroidDir;
std::string androidDataDir = volumeRoot + kAppDataDir;
diff --git a/Utils.h b/Utils.h
index 0eca902..8296ef8 100644
--- a/Utils.h
+++ b/Utils.h
@@ -205,6 +205,10 @@
status_t UnmountUserFuse(userid_t userId, const std::string& absolute_lower_path,
const std::string& relative_upper_path);
+status_t UnmountUserFuseEnhanced(userid_t userId, const std::string& absolute_lower_path,
+ const std::string& relative_upper_path,
+ const std::string& absolute_upper_path,
+ const std::vector<std::string>& bind_mount_paths = {});
status_t PrepareAndroidDirs(const std::string& volumeRoot);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 657f051..49a8b2b 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -452,36 +452,41 @@
if (mStartedUsers.find(userId) == mStartedUsers.end()) {
createEmulatedVolumesForUser(userId);
- std::list<std::string> public_vols;
- listVolumes(VolumeBase::Type::kPublic, public_vols);
- for (const std::string& id : public_vols) {
- PublicVolume* pvol = static_cast<PublicVolume*>(findVolume(id).get());
- if (pvol->getState() != VolumeBase::State::kMounted) {
- continue;
- }
- if (pvol->isVisible() == 0) {
- continue;
- }
- userid_t mountUserId = pvol->getMountUserId();
- if (userId == mountUserId) {
- // No need to bind mount for the user that owns the mount
- continue;
- }
- if (mountUserId != VolumeManager::Instance()->getSharedStorageUser(userId)) {
- // No need to bind if the user does not share storage with the mount owner
- continue;
- }
- // Create mount directory for the user as there is a chance that no other Volume is
- // mounted for the user (ex: if the user is just started), so /mnt/user/user_id does
- // not exist yet.
- auto mountDirStatus = android::vold::PrepareMountDirForUser(userId);
- if (mountDirStatus != OK) {
- LOG(ERROR) << "Failed to create Mount Directory for user " << userId;
- }
- auto bindMountStatus = pvol->bindMountForUser(userId);
- if (bindMountStatus != OK) {
- LOG(ERROR) << "Bind Mounting Public Volume: " << pvol << " for user: " << userId
- << "Failed. Error: " << bindMountStatus;
+
+ userid_t sharedStorageUserId = VolumeManager::Instance()->getSharedStorageUser(userId);
+ if (sharedStorageUserId != USER_UNKNOWN) {
+ std::list<std::string> public_vols;
+ listVolumes(VolumeBase::Type::kPublic, public_vols);
+ for (const std::string& id : public_vols) {
+ PublicVolume *pvol = static_cast<PublicVolume *>(findVolume(id).get());
+ if (pvol->getState() != VolumeBase::State::kMounted) {
+ continue;
+ }
+ if (pvol->isVisible() == 0) {
+ continue;
+ }
+ userid_t mountUserId = pvol->getMountUserId();
+ if (userId == mountUserId) {
+ // No need to bind mount for the user that owns the mount
+ continue;
+ }
+
+ if (mountUserId != sharedStorageUserId) {
+ // No need to bind if the user does not share storage with the mount owner
+ continue;
+ }
+ // Create mount directory for the user as there is a chance that no other Volume is
+ // mounted for the user (ex: if the user is just started),
+ // so /mnt/user/user_id does not exist yet.
+ auto mountDirStatus = android::vold::PrepareMountDirForUser(userId);
+ if (mountDirStatus != OK) {
+ LOG(ERROR) << "Failed to create Mount Directory for user " << userId;
+ }
+ auto bindMountStatus = pvol->bindMountForUser(userId);
+ if (bindMountStatus != OK) {
+ LOG(ERROR) << "Bind Mounting Public Volume: " << pvol << " for user: " << userId
+ << "Failed. Error: " << bindMountStatus;
+ }
}
}
}
@@ -497,6 +502,36 @@
if (mStartedUsers.find(userId) != mStartedUsers.end()) {
destroyEmulatedVolumesForUser(userId);
+
+ userid_t sharedStorageUserId = VolumeManager::Instance()->getSharedStorageUser(userId);
+ if (sharedStorageUserId != USER_UNKNOWN) {
+ std::list<std::string> public_vols;
+ listVolumes(VolumeBase::Type::kPublic, public_vols);
+ for (const std::string &id: public_vols) {
+ PublicVolume *pvol = static_cast<PublicVolume *>(findVolume(id).get());
+ if (pvol->getState() != VolumeBase::State::kMounted) {
+ continue;
+ }
+ if (pvol->isVisible() == 0) {
+ continue;
+ }
+ userid_t mountUserId = pvol->getMountUserId();
+ if (userId == mountUserId) {
+ // No need to remove bind mount for the user that owns the mount
+ continue;
+ }
+ if (mountUserId != sharedStorageUserId) {
+ // No need to remove bind mount
+ // if the user does not share storage with the mount owner
+ continue;
+ }
+ LOG(INFO) << "Removing Public Volume Bind Mount for: " << userId;
+ auto mountPath = GetFuseMountPathForUser(userId, pvol->getStableName());
+ android::vold::ForceUnmount(mountPath);
+ rmdir(mountPath.c_str());
+ }
+ }
+
}
mStartedUsers.erase(userId);
diff --git a/aconfig/flags.aconfig b/aconfig/flags.aconfig
new file mode 100644
index 0000000..d9c8fe2
--- /dev/null
+++ b/aconfig/flags.aconfig
@@ -0,0 +1,10 @@
+package: "android.vold.flags"
+container: "system"
+
+flag {
+ name: "enhance_fuse_unmount"
+ namespace: "mediaprovider"
+ description: "This flag controls whether enhancements to unmounting is enabled"
+ bug: "402367661"
+ is_fixed_read_only: true
+}
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 83d6c13..2df35cb 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -36,8 +36,11 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <android_vold_flags.h>
using android::base::StringPrintf;
+namespace flags = android::vold::flags;
+
namespace android {
namespace vold {
@@ -449,9 +452,17 @@
auto fuse_unmounter = [&]() {
LOG(INFO) << "fuse_unmounter scope_guard running";
fd.reset();
- if (UnmountUserFuse(user_id, getInternalPath(), label) != OK) {
- PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
+ if (flags::enhance_fuse_unmount()) {
+ std::string user_path(StringPrintf("%s/%d", getPath().c_str(), getMountUserId()));
+ if (UnmountUserFuseEnhanced(user_id, getInternalPath(), label, user_path) != OK) {
+ PLOG(INFO) << "UnmountUserFuseEnhanced failed on emulated fuse volume";
+ }
+ } else {
+ if (UnmountUserFuse(user_id, getInternalPath(), label) != OK) {
+ PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
+ }
}
+
mFuseMounted = false;
};
auto fuse_guard = android::base::make_scope_guard(fuse_unmounter);
@@ -507,21 +518,22 @@
status_t EmulatedVolume::doUnmount() {
int userId = getMountUserId();
- // Kill all processes using the filesystem before we unmount it. If we
- // unmount the filesystem first, most file system operations will return
- // ENOTCONN until the unmount completes. This is an exotic and unusual
- // error code and might cause broken behaviour in applications.
if (mFuseMounted) {
- // For FUSE specifically, we have an emulated volume per user, so only kill
- // processes using files from this particular user.
std::string user_path(StringPrintf("%s/%d", getPath().c_str(), getMountUserId()));
- LOG(INFO) << "Killing all processes referencing " << user_path;
- KillProcessesUsingPath(user_path);
- } else {
- KillProcessesUsingPath(getPath());
- }
- if (mFuseMounted) {
+ // We don't kill processes before trying to unmount in case enhance_fuse_unmount enabled
+ // As we make sure to kill processes if needed if unmounting failed
+ if (!flags::enhance_fuse_unmount()) {
+ // Kill all processes using the filesystem before we unmount it. If we
+ // unmount the filesystem first, most file system operations will return
+ // ENOTCONN until the unmount completes. This is an exotic and unusual
+ // error code and might cause broken behaviour in applications.
+ // For FUSE specifically, we have an emulated volume per user, so only kill
+ // processes using files from this particular user.
+ LOG(INFO) << "Killing all processes referencing " << user_path;
+ KillProcessesUsingPath(user_path);
+ }
+
std::string label = getLabel();
if (!IsFuseBpfEnabled()) {
@@ -530,12 +542,24 @@
unmountFuseBindMounts();
}
- if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
- PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
- return -errno;
+ if (flags::enhance_fuse_unmount()) {
+ status_t result = UnmountUserFuseEnhanced(userId, getInternalPath(), label, user_path);
+ if (result != OK) {
+ PLOG(INFO) << "UnmountUserFuseEnhanced failed on emulated fuse volume";
+ return result;
+ }
+ } else {
+ if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
+ PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
+ return -errno;
+ }
}
mFuseMounted = false;
+ } else {
+ // This branch is needed to help with unmounting private volumes that aren't set to primary
+ // and don't have fuse mounted but have stacked emulated volumes
+ KillProcessesUsingPath(getPath());
}
return unmountSdcardFs();
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index 91b1ca2..5a30fca 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -36,9 +36,11 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <android_vold_flags.h>
using android::base::GetBoolProperty;
using android::base::StringPrintf;
+namespace flags = android::vold::flags;
namespace android {
namespace vold {
@@ -88,6 +90,15 @@
return OK;
}
+std::string PublicVolume::getStableName() {
+ // Use UUID as stable name, if available
+ std::string stableName = getId();
+ if (!mFsUuid.empty()) {
+ stableName = mFsUuid;
+ }
+ return stableName;
+}
+
status_t PublicVolume::doCreate() {
return CreateDeviceNode(mDevPath, mDevice);
}
@@ -115,11 +126,7 @@
return -EIO;
}
- // Use UUID as stable name, if available
- std::string stableName = getId();
- if (!mFsUuid.empty()) {
- stableName = mFsUuid;
- }
+ std::string stableName = getStableName();
mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
@@ -286,10 +293,7 @@
status_t PublicVolume::bindMountForUser(userid_t user_id) {
userid_t mountUserId = getMountUserId();
- std::string stableName = getId();
- if (!mFsUuid.empty()) {
- stableName = mFsUuid;
- }
+ std::string stableName = getStableName();
LOG(INFO) << "Bind Mounting Public Volume for user: " << user_id
<< ".Mount owner: " << mountUserId;
@@ -307,34 +311,57 @@
// the FUSE process first, most file system operations will return
// ENOTCONN until the unmount completes. This is an exotic and unusual
// error code and might cause broken behaviour in applications.
- KillProcessesUsingPath(getPath());
+
+ // We don't kill processes here if enhance_fuse_unmount as we make sure that we kill processes
+ // only if unmounting failed
+ if (!mFuseMounted || !flags::enhance_fuse_unmount()) {
+ KillProcessesUsingPath(getPath());
+ }
if (mFuseMounted) {
- // Use UUID as stable name, if available
- std::string stableName = getId();
- if (!mFsUuid.empty()) {
- stableName = mFsUuid;
- }
+ std::string stableName = getStableName();
// Unmount bind mounts for running users
auto vol_manager = VolumeManager::Instance();
- int user_id = getMountUserId();
- for (int started_user : vol_manager->getStartedUsers()) {
+ userid_t user_id = getMountUserId();
+ std::vector<std::string> bind_mount_paths;
+ for (userid_t started_user : vol_manager->getStartedUsers()) {
if (started_user == user_id) {
// No need to remove bind mount for the user that owns the mount
continue;
}
- LOG(INFO) << "Removing Public Volume Bind Mount for: " << started_user;
+ if (user_id != VolumeManager::Instance()->getSharedStorageUser(started_user)) {
+ // No need to remove bind mount
+ // if the user does not share storage with the mount owner
+ continue;
+ }
+
auto mountPath = GetFuseMountPathForUser(started_user, stableName);
- ForceUnmount(mountPath);
- rmdir(mountPath.c_str());
+ if (flags::enhance_fuse_unmount()) {
+ // Add it to list so that we unmount it as part of UnmountUserFuseEnhanced
+ bind_mount_paths.push_back(mountPath);
+ } else {
+ LOG(INFO) << "Removing Public Volume Bind Mount for: " << started_user;
+ ForceUnmount(mountPath);
+ rmdir(mountPath.c_str());
+ }
}
- if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) {
- PLOG(INFO) << "UnmountUserFuse failed on public fuse volume";
- return -errno;
+ if (flags::enhance_fuse_unmount()) {
+ status_t result = UnmountUserFuseEnhanced(getMountUserId(), getInternalPath(),
+ stableName, getPath(), bind_mount_paths);
+ if (result != OK) {
+ PLOG(INFO) << "UnmountUserFuseEnhanced failed on public fuse volume";
+ return result;
+ }
+ } else {
+ if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) {
+ PLOG(INFO) << "UnmountUserFuse failed on public fuse volume";
+ return -errno;
+ }
}
+
mFuseMounted = false;
}
diff --git a/model/PublicVolume.h b/model/PublicVolume.h
index ca553b0..5eff35e 100644
--- a/model/PublicVolume.h
+++ b/model/PublicVolume.h
@@ -43,6 +43,7 @@
virtual ~PublicVolume();
status_t bindMountForUser(userid_t user_id);
+ std::string getStableName();
protected:
status_t doCreate() override;