lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <176602332527.688213.9644123318095990966.stgit@frogsfrogsfrogs>
Date: Wed, 17 Dec 2025 18:04:29 -0800
From: "Darrick J. Wong" <djwong@...nel.org>
To: brauner@...nel.org, djwong@...nel.org
Cc: linux-ext4@...r.kernel.org, linux-xfs@...r.kernel.org, hch@....de,
 linux-fsdevel@...r.kernel.org
Subject: [PATCH 1/4] fs: send uevents for filesystem mount events

From: Darrick J. Wong <djwong@...nel.org>

Add the ability to send uevents whenever a filesystem mounts, unmounts,
or goes down.  This will enable XFS to start daemons whenever a
filesystem is first mounted.

Regrettably, we can't wire this directly into get_tree_bdev_flags or
generic_shutdown_super because not all filesystems set up a kobject
representation in sysfs, and the VFS has no idea if a filesystem
actually does that.

Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
---
 include/linux/fsevent.h |   33 ++++++++++++
 fs/Makefile             |    2 -
 fs/fsevent.c            |  128 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/fsevent.h
 create mode 100644 fs/fsevent.c


diff --git a/include/linux/fsevent.h b/include/linux/fsevent.h
new file mode 100644
index 00000000000000..548e35861e545f
--- /dev/null
+++ b/include/linux/fsevent.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2025 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@...nel.org>
+ */
+#ifndef _LINUX_FSEVENT_H__
+#define _LINUX_FSEVENT_H__
+
+void fsevent_send_mount(struct super_block *sb, struct kobject *kobject,
+			struct fs_context *fc);
+
+void fsevent_send(struct super_block *sb, struct kobject *kobject,
+		  enum kobject_action kaction);
+
+static inline void fsevent_send_unmount(struct super_block *sb,
+					struct kobject *kobject)
+{
+	fsevent_send(sb, kobject, KOBJ_REMOVE);
+}
+
+static inline void fsevent_send_remount(struct super_block *sb,
+					struct kobject *kobject)
+{
+	fsevent_send(sb, kobject, KOBJ_CHANGE);
+}
+
+static inline void fsevent_send_shutdown(struct super_block *sb,
+					 struct kobject *kobject)
+{
+	fsevent_send(sb, kobject, KOBJ_OFFLINE);
+}
+
+#endif /* _LINUX_FSEVENT_H__ */
diff --git a/fs/Makefile b/fs/Makefile
index f238cc5ea2e9d7..4a07ae61e65730 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -16,7 +16,7 @@ obj-y :=	open.o read_write.o file_table.o super.o \
 		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
 		fs_dirent.o fs_context.o fs_parser.o fsopen.o init.o \
 		kernel_read_file.o mnt_idmapping.o remap_range.o pidfs.o \
-		file_attr.o fserror.o
+		file_attr.o fserror.o fsevent.o
 
 obj-$(CONFIG_BUFFER_HEAD)	+= buffer.o mpage.o
 obj-$(CONFIG_PROC_FS)		+= proc_namespace.o
diff --git a/fs/fsevent.c b/fs/fsevent.c
new file mode 100644
index 00000000000000..a7eea8eac0578a
--- /dev/null
+++ b/fs/fsevent.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@...nel.org>
+ */
+#include <linux/fs.h>
+#include <linux/kobject.h>
+#include <linux/fs_context.h>
+#include <linux/fsevent.h>
+
+static inline size_t fs_uevent_bufsize(const struct super_block *sb,
+				       const char *source,
+				       unsigned int *envlen)
+{
+	size_t ret = sizeof("TYPE=filesystem") +
+		     sizeof("SID=") + sizeof_field(struct super_block, s_id);
+	*envlen += 2;
+
+	if (source) {
+		ret += sizeof("SOURCE=") + strlen(source) + 1;
+		(*envlen)++;
+	}
+
+	if (sb->s_uuid_len == sizeof(sb->s_uuid)) {
+		ret += sizeof("UUID=") + UUID_STRING_LEN;
+		(*envlen)++;
+	}
+
+	/* null array element terminator */
+	(*envlen)++;
+	return ret;
+}
+
+#define ADVANCE_ENV(envp, buf, buflen, written) \
+	do { \
+		ssize_t __written = (written); \
+\
+		WARN_ON((buflen) < (__written) + 1); \
+		*(envp) = (buf); \
+		(envp)++; \
+		(buf) += (__written) + 1; \
+		(buflen) -= (__written) + 1; \
+	} while (0)
+
+static char **format_uevent_strings(struct super_block *sb, const char *source)
+{
+	unsigned int envlen = 0;
+	size_t buflen = fs_uevent_bufsize(sb, source, &envlen);
+	char *buf;
+	char **env, **envp;
+	ssize_t written;
+
+	buf = kzalloc(buflen, GFP_KERNEL);
+	if (!buf)
+		return NULL;
+	env = kcalloc(envlen, sizeof(char *), GFP_KERNEL);
+	if (!env) {
+		kfree(buf);
+		return NULL;
+	}
+
+	envp = env;
+	written = snprintf(buf, buflen, "TYPE=filesystem");
+	if (written >= buflen)
+		goto bad;
+	ADVANCE_ENV(envp, buf, buflen, written);
+
+	written = snprintf(buf, buflen, "SID=%s", sb->s_id);
+	if (written >= buflen)
+		goto bad;
+	ADVANCE_ENV(envp, buf, buflen, written);
+
+	if (source) {
+		written = snprintf(buf, buflen, "SOURCE=%s", source);
+		if (written >= buflen)
+			goto bad;
+		ADVANCE_ENV(envp, buf, buflen, written);
+	}
+
+	if (sb->s_uuid_len == sizeof(sb->s_uuid)) {
+		written = snprintf(buf, buflen, "UUID=%pU", &sb->s_uuid);
+		if (written >= buflen)
+			goto bad;
+		ADVANCE_ENV(envp, buf, buflen, written);
+	}
+
+	return env;
+bad:
+	kfree(env);
+	kfree(buf);
+	return NULL;
+}
+
+static inline void free_uevent_strings(char **env)
+{
+	kfree(env[0]);
+	kfree(env);
+}
+
+/*
+ * Send a uevent signalling that the mount succeeded so we can use udev rules
+ * to start background services.
+ */
+void fsevent_send_mount(struct super_block *sb, struct kobject *kobject,
+			struct fs_context *fc)
+{
+	char **env = format_uevent_strings(sb, fc->source);
+
+	if (env) {
+		kobject_uevent_env(kobject, KOBJ_ADD, env);
+		free_uevent_strings(env);
+	}
+}
+EXPORT_SYMBOL_GPL(fsevent_send_mount);
+
+/* Send a uevent signalling that something happened to a live mount. */
+void fsevent_send(struct super_block *sb, struct kobject *kobject,
+		  enum kobject_action kaction)
+{
+	char **env;
+
+	env = format_uevent_strings(sb, NULL);
+	if (env) {
+		kobject_uevent_env(kobject, kaction, env);
+		free_uevent_strings(env);
+	}
+}
+EXPORT_SYMBOL_GPL(fsevent_send);


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ