diff --git a/EmulatedVolume.cpp b/EmulatedVolume.cpp index 6e440cc..80ef3e2 100644 --- a/EmulatedVolume.cpp +++ b/EmulatedVolume.cpp @@ -113,6 +113,7 @@ status_t EmulatedVolume::doUnmount() { mFusePid = 0; } + KillProcessesUsingPath(getPath()); ForceUnmount(mFuseDefault); ForceUnmount(mFuseRead); ForceUnmount(mFuseWrite); diff --git a/Process.cpp b/Process.cpp index a6f0cc6..962a460 100644 --- a/Process.cpp +++ b/Process.cpp @@ -177,13 +177,14 @@ extern "C" void vold_killProcessesWithOpenFiles(const char *path, int signal) { /* * Hunt down processes that have files open at the given mount point. */ -void Process::killProcessesWithOpenFiles(const char *path, int signal) { - DIR* dir; +int Process::killProcessesWithOpenFiles(const char *path, int signal) { + int count = 0; + DIR* dir; struct dirent* de; if (!(dir = opendir("/proc"))) { SLOGE("opendir failed (%s)", strerror(errno)); - return; + return count; } while ((de = readdir(dir))) { @@ -213,7 +214,9 @@ void Process::killProcessesWithOpenFiles(const char *path, int signal) { if (signal != 0) { SLOGW("Sending %s to process %d", strsignal(signal), pid); kill(pid, signal); + count++; } } closedir(dir); + return count; } diff --git a/Process.h b/Process.h index 81b5f18..62a9313 100644 --- a/Process.h +++ b/Process.h @@ -21,7 +21,7 @@ class Process { public: - static void killProcessesWithOpenFiles(const char *path, int signal); + static int killProcessesWithOpenFiles(const char *path, int signal); static int getPid(const char *s); static int checkSymLink(int pid, const char *path, const char *name); static int checkFileMaps(int pid, const char *path); diff --git a/Utils.cpp b/Utils.cpp index e19c9df..f352e84 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -123,35 +123,57 @@ status_t ForceUnmount(const std::string& path) { if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } - PLOG(WARNING) << "Failed to unmount " << path; - + // Apps might still be handling eject request, so wait before + // we start sending signals sleep(5); + Process::killProcessesWithOpenFiles(cpath, SIGINT); - + sleep(5); if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } - PLOG(WARNING) << "Failed to unmount " << path; - sleep(5); Process::killProcessesWithOpenFiles(cpath, SIGTERM); - - if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { - return OK; - } - PLOG(WARNING) << "Failed to unmount " << path; - sleep(5); - Process::killProcessesWithOpenFiles(cpath, SIGKILL); - if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } - PLOG(ERROR) << "Failed to unmount " << path; + + Process::killProcessesWithOpenFiles(cpath, SIGKILL); + sleep(5); + if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { + return OK; + } return -errno; } +status_t KillProcessesUsingPath(const std::string& path) { + const char* cpath = path.c_str(); + if (Process::killProcessesWithOpenFiles(cpath, SIGINT) == 0) { + return OK; + } + sleep(5); + + if (Process::killProcessesWithOpenFiles(cpath, SIGTERM) == 0) { + return OK; + } + sleep(5); + + if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) { + return OK; + } + sleep(5); + + // Send SIGKILL a second time to determine if we've + // actually killed everyone with open files + if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) { + return OK; + } + PLOG(ERROR) << "Failed to kill processes using " << path; + return -EBUSY; +} + status_t BindMount(const std::string& source, const std::string& target) { if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) { PLOG(ERROR) << "Failed to bind mount " << source << " to " << target; diff --git a/Utils.h b/Utils.h index f33a379..228727a 100644 --- a/Utils.h +++ b/Utils.h @@ -49,6 +49,9 @@ status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid); /* Really unmounts the path, killing active processes along the way */ status_t ForceUnmount(const std::string& path); +/* Kills any processes using given path */ +status_t KillProcessesUsingPath(const std::string& path); + /* Creates bind mount from source to target */ status_t BindMount(const std::string& source, const std::string& target);