Netdev List
 help / color / mirror / Atom feed
* [RFC PATCH v2 03/11] dns_resolver: Clear .dns_resolver cache when the last client unloads
       [not found] <20261103030226.2685251-1-jarkko@kernel.org>
@ 2026-11-03  3:02 ` Jarkko Sakkinen
  0 siblings, 0 replies; only message in thread
From: Jarkko Sakkinen @ 2026-11-03  3:02 UTC (permalink / raw)
  To: David Howells
  Cc: Eric Biggers, linux-integrity, Mimi Zohar, keyrings,
	Jarkko Sakkinen, Marc Dionne, Trond Myklebust, Anna Schumaker,
	Paulo Alcantara, Namjae Jeon, Ronnie Sahlberg, Shyam Prasad N,
	Tom Talpey, Bharath SM, Ilya Dryomov, Alex Markuze, Xiubo Li,
	Viacheslav Dubeyko, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Roberto Sassu, Dmitry Kasatkin,
	Eric Snowberg, Paul Moore, James Morris, Serge E. Hallyn,
	Thorsten Blum, Tim Bird, open list:AFS FILESYSTEM, open list,
	open list:NFS, SUNRPC, AND LOCKD CLIENTS,
	open list:COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3),
	moderated list:COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3),
	open list:CEPH COMMON CODE (LIBCEPH),
	open list:NETWORKING [GENERAL], open list:SECURITY SUBSYSTEM

dns_query() caches resolved dns_resolver keys into the module-owned
.dns_resolver keyring until the TTL expires or module_exit() revokes the
keyring.

Once live keys pin their key type, cached entries keep dns_resolver.ko
pinned after its client modules unload.

Track active kernel client modules with dns_resolver_cache_get() and
dns_resolver_cache_put(), and do the necessary plumbing for:

1. nfsv4
2. cifs
3. libceph
4. kafs

When the last client unloads, clear .dns_resolver and flush key garbage
collection so dns_resolver.ko can unload immediately.

Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 fs/afs/main.c                |  4 ++++
 fs/nfs/dns_resolve.h         |  7 ++++++-
 fs/smb/client/cifsfs.c       |  4 ++++
 include/linux/dns_resolver.h | 13 ++++++++++---
 net/ceph/ceph_common.c       |  7 +++++++
 net/dns_resolver/dns_key.c   | 28 ++++++++++++++++++++++++++++
 6 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/fs/afs/main.c b/fs/afs/main.c
index 7a883c59976f..16ae947d371e 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -12,6 +12,7 @@
 #include <linux/sched.h>
 #include <linux/random.h>
 #include <linux/proc_fs.h>
+#include <linux/dns_resolver.h>
 #define CREATE_TRACE_POINTS
 #include "internal.h"
 
@@ -183,6 +184,7 @@ static int __init afs_init(void)
 	if (ret < 0)
 		goto error_net;
 
+	dns_resolver_cache_get();
 	/* register the filesystems */
 	ret = afs_fs_init();
 	if (ret < 0)
@@ -199,6 +201,7 @@ static int __init afs_init(void)
 error_proc:
 	afs_fs_exit();
 error_fs:
+	dns_resolver_cache_put();
 	unregister_pernet_device(&afs_net_ops);
 error_net:
 	destroy_workqueue(afs_lock_manager);
@@ -232,6 +235,7 @@ static void __exit afs_exit(void)
 	destroy_workqueue(afs_wq);
 	afs_clean_up_permit_cache();
 	rcu_barrier();
+	dns_resolver_cache_put();
 }
 
 module_exit(afs_exit);
diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h
index fe3b172c4de1..4b9ecfb4f7fe 100644
--- a/fs/nfs/dns_resolve.h
+++ b/fs/nfs/dns_resolve.h
@@ -9,13 +9,18 @@
 
 
 #ifdef CONFIG_NFS_USE_KERNEL_DNS
+#include <linux/dns_resolver.h>
+
 static inline int nfs_dns_resolver_init(void)
 {
+	dns_resolver_cache_get();
 	return 0;
 }
 
 static inline void nfs_dns_resolver_destroy(void)
-{}
+{
+	dns_resolver_cache_put();
+}
 
 static inline int nfs_dns_resolver_cache_init(struct net *net)
 {
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index bf199a5ca084..9788052599ce 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -31,6 +31,7 @@
 #include <linux/xattr.h>
 #include <linux/mm.h>
 #include <linux/key-type.h>
+#include <linux/dns_resolver.h>
 #include <linux/fileattr.h>
 #include <uapi/linux/magic.h>
 #include <net/ipv6.h>
@@ -2160,6 +2161,7 @@ init_cifs(void)
 		goto out_cifs_swn_init;
 
 	cifs_proc_init();
+	dns_resolver_cache_get();
 
 	rc = register_filesystem(&cifs_fs_type);
 	if (rc)
@@ -2174,6 +2176,7 @@ init_cifs(void)
 	return 0;
 
 out_clean_proc:
+	dns_resolver_cache_put();
 	cifs_proc_clean();
 	exit_cifs_idmap();
 out_cifs_swn_init:
@@ -2242,6 +2245,7 @@ exit_cifs(void)
 	destroy_workqueue(serverclose_wq);
 	destroy_workqueue(cfid_put_wq);
 	destroy_workqueue(cifsiod_wq);
+	dns_resolver_cache_put();
 }
 
 MODULE_AUTHOR("Steve French");
diff --git a/include/linux/dns_resolver.h b/include/linux/dns_resolver.h
index 976cbbdb2832..cc11e09b0df3 100644
--- a/include/linux/dns_resolver.h
+++ b/include/linux/dns_resolver.h
@@ -27,8 +27,15 @@
 #include <uapi/linux/dns_resolver.h>
 
 struct net;
-extern int dns_query(struct net *net, const char *type, const char *name, size_t namelen,
-		     const char *options, char **_result, time64_t *_expiry,
-		     bool invalidate);
+#if IS_ENABLED(CONFIG_DNS_RESOLVER)
+int dns_query(struct net *net, const char *type, const char *name, size_t namelen,
+	      const char *options, char **_result, time64_t *_expiry,
+	      bool invalidate);
+void dns_resolver_cache_get(void);
+void dns_resolver_cache_put(void);
+#else
+static inline void dns_resolver_cache_get(void) { }
+static inline void dns_resolver_cache_put(void) { }
+#endif
 
 #endif /* _LINUX_DNS_RESOLVER_H */
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index a797c7360e3c..df62a269cb73 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -8,6 +8,7 @@
 #include <linux/in6.h>
 #include <linux/key.h>
 #include <keys/ceph-type.h>
+#include <linux/dns_resolver.h>
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/nsproxy.h>
@@ -890,6 +891,9 @@ static int __init init_ceph_lib(void)
 	if (ret < 0)
 		goto out_msgr;
 
+#ifdef CONFIG_CEPH_LIB_USE_DNS_RESOLVER
+	dns_resolver_cache_get();
+#endif
 	pr_info("loaded (mon/osd proto %d/%d)\n",
 		CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL);
 
@@ -913,6 +917,9 @@ static void __exit exit_ceph_lib(void)
 	ceph_msgr_exit();
 	ceph_crypto_shutdown();
 	ceph_debugfs_cleanup();
+#ifdef CONFIG_CEPH_LIB_USE_DNS_RESOLVER
+	dns_resolver_cache_put();
+#endif
 }
 
 module_init(init_ceph_lib);
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index 451247864a63..63f4fac0dbc8 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/keyctl.h>
 #include <linux/err.h>
+#include <linux/mutex.h>
 #include <linux/seq_file.h>
 #include <linux/dns_resolver.h>
 #include <keys/dns_resolver-type.h>
@@ -31,6 +32,8 @@ module_param_named(debug, dns_resolver_debug, uint, 0644);
 MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
 
 const struct cred *dns_resolver_cache;
+static DEFINE_MUTEX(dns_resolver_cache_mutex);
+static unsigned int dns_resolver_cache_users;
 
 #define	DNS_ERRORNO_OPTION	"dnserror"
 
@@ -306,6 +309,31 @@ static long dns_resolver_read(const struct key *key,
 	return user_read(key, buffer, buflen);
 }
 
+void dns_resolver_cache_get(void)
+{
+	mutex_lock(&dns_resolver_cache_mutex);
+	dns_resolver_cache_users++;
+	mutex_unlock(&dns_resolver_cache_mutex);
+}
+EXPORT_SYMBOL_GPL(dns_resolver_cache_get);
+
+void dns_resolver_cache_put(void)
+{
+	int ret;
+
+	mutex_lock(&dns_resolver_cache_mutex);
+	if (--dns_resolver_cache_users == 0 && dns_resolver_cache) {
+		ret = keyring_clear(dns_resolver_cache->thread_keyring);
+		if (ret)
+			pr_warn_ratelimited("dns_resolver: Failed to clear cache: %d\n",
+					    ret);
+		else
+			key_gc_flush();
+	}
+	mutex_unlock(&dns_resolver_cache_mutex);
+}
+EXPORT_SYMBOL_GPL(dns_resolver_cache_put);
+
 struct key_type key_type_dns_resolver = {
 	.name		= "dns_resolver",
 	.flags		= KEY_TYPE_NET_DOMAIN | KEY_TYPE_INSTANT_REAP,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-11-03  3:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20261103030226.2685251-1-jarkko@kernel.org>
2026-11-03  3:02 ` [RFC PATCH v2 03/11] dns_resolver: Clear .dns_resolver cache when the last client unloads Jarkko Sakkinen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox