summaryrefslogtreecommitdiffstats
path: root/src/shutdown
diff options
context:
space:
mode:
authorJan Janssen <medhefgo@web.de>2022-05-11 11:10:11 +0200
committerJan Janssen <medhefgo@web.de>2022-06-09 17:00:46 +0200
commit20596876e3031e05304061ec1fb080646fcef5ba (patch)
tree7200908c89ffbdfad71bb6b5b8c17673046b9a00 /src/shutdown
parentshutdown: Rename umount_log_level and make it a bool (diff)
downloadsystemd-20596876e3031e05304061ec1fb080646fcef5ba.tar.xz
systemd-20596876e3031e05304061ec1fb080646fcef5ba.zip
shutdown: Log processes that block umount
Diffstat (limited to 'src/shutdown')
-rw-r--r--src/shutdown/umount.c66
1 files changed, 63 insertions, 3 deletions
diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c
index fc09fde668..243a1f80ef 100644
--- a/src/shutdown/umount.c
+++ b/src/shutdown/umount.c
@@ -25,13 +25,17 @@
#include "blockdev-util.h"
#include "def.h"
#include "device-util.h"
+#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "fstab-util.h"
#include "libmount-util.h"
#include "mount-setup.h"
#include "mount-util.h"
#include "mountpoint-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "signal-util.h"
@@ -524,6 +528,58 @@ static bool nonunmountable_path(const char *path) {
|| path_startswith(path, "/run/initramfs");
}
+static void log_umount_blockers(const char *mnt) {
+ _cleanup_closedir_ DIR *dir = opendir("/proc");
+ if (!dir)
+ return (void) log_warning_errno(errno, "opendir(/proc) failed: %m");
+
+ _cleanup_free_ char *blockers = NULL;
+
+ FOREACH_DIRENT_ALL(de, dir, break) {
+ if (!IN_SET(de->d_type, DT_DIR, DT_UNKNOWN))
+ continue;
+
+ pid_t pid;
+ if (parse_pid(de->d_name, &pid) < 0)
+ continue;
+
+ _cleanup_closedir_ DIR *pid_dir = xopendirat(dirfd(dir), de->d_name, 0);
+ if (!pid_dir)
+ continue;
+
+ _cleanup_closedir_ DIR *fd_dir = xopendirat(dirfd(pid_dir), "fd", 0);
+ if (!fd_dir)
+ continue;
+
+ FOREACH_DIRENT(fd_de, fd_dir, break) {
+ _cleanup_free_ char *open_file = NULL, *comm = NULL;
+
+ if (readlinkat_malloc(dirfd(fd_dir), fd_de->d_name, &open_file) < 0)
+ continue;
+
+ if (!path_startswith(open_file, mnt))
+ continue;
+
+ if (PATH_STARTSWITH_SET(open_file, "/dev", "/sys", "/proc"))
+ continue;
+
+ if (get_process_comm(pid, &comm) < 0)
+ continue;
+
+ if (!strextend_with_separator(&blockers, ", ", comm))
+ return (void) log_oom();
+
+ if (!strextend(&blockers, "(", de->d_name, ")"))
+ return (void) log_oom();
+
+ break;
+ }
+ }
+
+ if (blockers)
+ log_warning("Unmounting '%s' blocked by: %s", mnt, blockers);
+}
+
static int remount_with_timeout(MountPoint *m, bool last_try) {
pid_t pid;
int r;
@@ -586,9 +642,13 @@ static int umount_with_timeout(MountPoint *m, bool last_try) {
* "busy", this may allow processes to die, thus making the
* filesystem less busy so the unmount might succeed (rather
* than return EBUSY). */
- r = umount2(m->path, MNT_FORCE);
- if (r < 0)
- log_full_errno(last_try ? LOG_ERR : LOG_INFO, errno, "Failed to unmount %s: %m", m->path);
+ r = RET_NERRNO(umount2(m->path, MNT_FORCE));
+ if (r < 0) {
+ log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Failed to unmount %s: %m", m->path);
+
+ if (r == -EBUSY && last_try)
+ log_umount_blockers(m->path);
+ }
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}