summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-04-11 21:52:49 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-09-03 05:01:52 +0900
commit1055172804e660df2e1c498dafa998ffd65e0c88 (patch)
treef551de6955888afd5afcfe11916f8bcf4463d224 /src
parent57a272902aa821f9598dd0d74eab98d287473a63 (diff)
downloadsystemd-1055172804e660df2e1c498dafa998ffd65e0c88.tar.gz
udev: cleanup stack directory /run/udev/links when all workers exited
By the previous commit, the stack directories are not removed even if it is empty. To reduce the inode usage of /run, let's cleanup the directories.
Diffstat (limited to 'src')
-rw-r--r--src/udev/udev-node.c42
-rw-r--r--src/udev/udev-node.h1
-rw-r--r--src/udev/udevd.c10
3 files changed, 53 insertions, 0 deletions
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index 42efaaa028..4e7dca06de 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -26,6 +26,48 @@
#define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
+int udev_node_cleanup(void) {
+ _cleanup_closedir_ DIR *dir = NULL;
+
+ /* This must not be called when any workers exist. It would cause a race between mkdir() called
+ * by stack_directory_lock() and unlinkat() called by this. */
+
+ dir = opendir("/run/udev/links");
+ if (!dir) {
+ if (errno == ENOENT)
+ return 0;
+
+ return log_debug_errno(errno, "Failed to open directory '/run/udev/links', ignoring: %m");
+ }
+
+ FOREACH_DIRENT_ALL(de, dir, break) {
+ _cleanup_free_ char *lockfile = NULL;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (de->d_type != DT_DIR)
+ continue;
+
+ /* As commented in the above, this is called when no worker exists, hence the file is not
+ * locked. On a later uevent, the lock file will be created if necessary. So, we can safely
+ * remove the file now. */
+ lockfile = path_join(de->d_name, ".lock");
+ if (!lockfile)
+ return log_oom_debug();
+
+ if (unlinkat(dirfd(dir), lockfile, 0) < 0 && errno != ENOENT) {
+ log_debug_errno(errno, "Failed to remove '/run/udev/links/%s', ignoring: %m", lockfile);
+ continue;
+ }
+
+ if (unlinkat(dirfd(dir), de->d_name, AT_REMOVEDIR) < 0 && errno != ENOTEMPTY)
+ log_debug_errno(errno, "Failed to remove '/run/udev/links/%s', ignoring: %m", de->d_name);
+ }
+
+ return 0;
+}
+
static int node_symlink(sd_device *dev, const char *devnode, const char *slink) {
_cleanup_free_ char *target = NULL;
const char *id, *slink_tmp;
diff --git a/src/udev/udev-node.h b/src/udev/udev-node.h
index 86a829545a..0c545e4a0f 100644
--- a/src/udev/udev-node.h
+++ b/src/udev/udev-node.h
@@ -24,5 +24,6 @@ int static_node_apply_permissions(
int udev_node_remove(sd_device *dev);
int udev_node_update(sd_device *dev, sd_device *dev_old);
+int udev_node_cleanup(void);
size_t udev_node_escape_path(const char *src, char *dest, size_t size);
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index b179dfac37..c519e19897 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -65,6 +65,7 @@
#include "udev-builtin.h"
#include "udev-ctrl.h"
#include "udev-event.h"
+#include "udev-node.h"
#include "udev-util.h"
#include "udev-watch.h"
#include "user-util.h"
@@ -111,6 +112,7 @@ typedef struct Manager {
usec_t last_usec;
+ bool udev_node_needs_cleanup;
bool stop_exec_queue;
bool exit;
} Manager;
@@ -976,6 +978,9 @@ static int event_queue_start(Manager *manager) {
if (!manager->events || manager->exit || manager->stop_exec_queue)
return 0;
+ /* To make the stack directory /run/udev/links cleaned up later. */
+ manager->udev_node_needs_cleanup = true;
+
r = event_source_disable(manager->kill_workers_event);
if (r < 0)
log_warning_errno(r, "Failed to disable event source for cleaning up idle workers, ignoring: %m");
@@ -1607,6 +1612,11 @@ static int on_post(sd_event_source *s, void *userdata) {
/* There are no idle workers. */
+ if (manager->udev_node_needs_cleanup) {
+ (void) udev_node_cleanup();
+ manager->udev_node_needs_cleanup = false;
+ }
+
if (manager->exit)
return sd_event_exit(manager->event, 0);