From: nspmangalore@gmail.com
To: linux-cifs@vger.kernel.org, smfrench@gmail.com, pc@manguebit.org,
bharathsm@microsoft.com, dhowells@redhat.com,
henrique.carvalho@suse.com, ematsumiya@suse.de
Cc: Shyam Prasad N <sprasad@microsoft.com>
Subject: [PATCH v5 10/17] cifs: register a shrinker to manage cached_dirents
Date: Thu, 14 May 2026 23:38:16 +0530 [thread overview]
Message-ID: <20260514180823.497293-10-sprasad@microsoft.com> (raw)
In-Reply-To: <20260514180823.497293-1-sprasad@microsoft.com>
From: Shyam Prasad N <sprasad@microsoft.com>
Since the cached_dirents are now backed by folioq, we do not need
a timed cleanup of these cfids anymore. This change registers a
shrinker with the mm layer for the dircache. If mm needs to free up
memory or flush the cache, it can inform cifs about this using the
shrinker interface.
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
---
fs/smb/client/cifs_debug.c | 18 +------
fs/smb/client/cifsfs.c | 104 ++++++++++++++++++++++++++++++++++++-
fs/smb/client/cifsfs.h | 4 ++
3 files changed, 108 insertions(+), 18 deletions(-)
diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
index b35863eb2a660..131af7333fc58 100644
--- a/fs/smb/client/cifs_debug.c
+++ b/fs/smb/client/cifs_debug.c
@@ -375,22 +375,8 @@ static ssize_t cifs_debug_dirs_proc_write(struct file *file, const char __user *
if (rc)
return rc;
- if (v == 0) {
- struct TCP_Server_Info *server;
- struct cifs_ses *ses;
- struct cifs_tcon *tcon;
-
- spin_lock(&cifs_tcp_ses_lock);
- list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
- list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
- if (cifs_ses_exiting(ses))
- continue;
- list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
- invalidate_all_cached_dirs(tcon, false);
- }
- }
- spin_unlock(&cifs_tcp_ses_lock);
- }
+ if (v == 0)
+ cifs_shrink_dir_caches(false, ULONG_MAX);
return count;
}
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 9f76b0347fa9d..14cb3d37a8607 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -29,6 +29,7 @@
#include <linux/uuid.h>
#include <linux/xattr.h>
#include <linux/mm.h>
+#include <linux/shrinker.h>
#include <linux/key-type.h>
#include <uapi/linux/magic.h>
#include <net/ipv6.h>
@@ -123,10 +124,95 @@ MODULE_PARM_DESC(dir_cache_timeout, "Number of seconds to cache directory conten
"Range: 1 to 65000 seconds, 0 to disable caching dir contents");
/* Module-wide total cached dirents (in bytes) across all tcons */
atomic64_t cifs_dircache_bytes_used = ATOMIC64_INIT(0);
+static struct shrinker *cifs_dircache_shrinker;
atomic_t cifs_sillycounter;
atomic_t cifs_tmpcounter;
+/**
+ * cifs_shrink_dir_caches - shrink dir caches by a specific size
+ * @wait: wait for server responses to close
+ * @nr_to_free: number of pages to shrink the dir cache by (pass ULONG_MAX to
+ * free everything)
+ *
+ * Shrinks dir caches by a specific target size.
+ */
+unsigned long cifs_shrink_dir_caches(bool wait, unsigned long nr_to_free)
+{
+ struct TCP_Server_Info *server;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+ u64 before, after, freed_bytes = 0;
+ u64 target_bytes;
+
+ before = atomic64_read(&cifs_dircache_bytes_used);
+ if (nr_to_free == ULONG_MAX)
+ target_bytes = U64_MAX;
+ else
+ target_bytes = (u64)nr_to_free * PAGE_SIZE;
+
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
+ list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+ if (cifs_ses_exiting(ses))
+ continue;
+ list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+ invalidate_all_cached_dirs(tcon, false);
+ after = atomic64_read(&cifs_dircache_bytes_used);
+ if (after < before)
+ freed_bytes = before - after;
+ if (freed_bytes >= target_bytes)
+ goto out_unlock;
+ }
+ }
+ }
+out_unlock:
+ spin_unlock(&cifs_tcp_ses_lock);
+
+ if (wait)
+ flush_workqueue(cfid_put_wq);
+
+ after = atomic64_read(&cifs_dircache_bytes_used);
+ if (after >= before)
+ return 0;
+ return (unsigned long)(before - after);
+}
+
+static unsigned long cifs_dircache_shrinker_count(struct shrinker *shrink,
+ struct shrink_control *sc)
+{
+ u64 bytes = atomic64_read(&cifs_dircache_bytes_used);
+
+ (void)shrink;
+ (void)sc;
+
+ return DIV_ROUND_UP_ULL(bytes, PAGE_SIZE);
+}
+
+static unsigned long cifs_dircache_shrinker_scan(struct shrinker *shrink,
+ struct shrink_control *sc)
+{
+ unsigned long freed_bytes;
+
+ (void)shrink;
+
+ if (!sc->nr_to_scan)
+ return 0;
+
+ if (!atomic64_read(&cifs_dircache_bytes_used))
+ return SHRINK_STOP;
+
+ /*
+ * Shrinker scan can run from reclaim context, so avoid synchronously
+ * flushing worker queues here to prevent long stalls/deadlocks.
+ */
+ freed_bytes = cifs_shrink_dir_caches(false, max_t(unsigned long, 1, sc->nr_to_scan));
+ if (!freed_bytes)
+ return SHRINK_STOP;
+
+ return DIV_ROUND_UP_ULL(freed_bytes, PAGE_SIZE);
+}
+
#ifdef CONFIG_CIFS_STATS2
unsigned int slow_rsp_threshold = 1;
module_param(slow_rsp_threshold, uint, 0644);
@@ -2011,10 +2097,19 @@ init_cifs(void)
if (rc)
goto out_destroy_mids;
+ cifs_dircache_shrinker = shrinker_alloc(0, "cifs-dircache");
+ if (!cifs_dircache_shrinker) {
+ rc = -ENOMEM;
+ goto out_destroy_request_bufs;
+ }
+ cifs_dircache_shrinker->count_objects = cifs_dircache_shrinker_count;
+ cifs_dircache_shrinker->scan_objects = cifs_dircache_shrinker_scan;
+ shrinker_register(cifs_dircache_shrinker);
+
#ifdef CONFIG_CIFS_DFS_UPCALL
rc = dfs_cache_init();
if (rc)
- goto out_destroy_request_bufs;
+ goto out_free_dircache_shrinker;
#endif /* CONFIG_CIFS_DFS_UPCALL */
#ifdef CONFIG_CIFS_UPCALL
rc = init_cifs_spnego();
@@ -2056,8 +2151,11 @@ init_cifs(void)
#endif
#ifdef CONFIG_CIFS_DFS_UPCALL
dfs_cache_destroy();
-out_destroy_request_bufs:
+out_free_dircache_shrinker:
#endif
+ shrinker_free(cifs_dircache_shrinker);
+ cifs_dircache_shrinker = NULL;
+out_destroy_request_bufs:
cifs_destroy_request_bufs();
out_destroy_mids:
destroy_mids();
@@ -2090,6 +2188,8 @@ exit_cifs(void)
cifs_dbg(NOISY, "exit_smb3\n");
unregister_filesystem(&cifs_fs_type);
unregister_filesystem(&smb3_fs_type);
+ shrinker_free(cifs_dircache_shrinker);
+ cifs_dircache_shrinker = NULL;
cifs_release_automount_timer();
exit_cifs_idmap();
#ifdef CONFIG_CIFS_SWN_UPCALL
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index c455b15f27782..d08394a3c5ce5 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -122,6 +122,10 @@ extern const struct dentry_operations cifs_ci_dentry_ops;
struct vfsmount *cifs_d_automount(struct path *path);
+/* Functions related to dir cache */
+unsigned long cifs_shrink_dir_caches(bool wait,
+ unsigned long nr_to_free);
+
/* Functions related to symlinks */
const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
struct delayed_call *done);
--
2.43.0
next prev parent reply other threads:[~2026-05-14 18:08 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-14 18:08 [PATCH v5 01/17] cifs: invalidate cfid on unlink/rename/rmdir nspmangalore
2026-05-14 18:08 ` [PATCH v5 02/17] cifs: define variable sized buffer for querydir responses nspmangalore
2026-05-14 18:08 ` [PATCH v5 03/17] cifs: optimize readdir for small directories nspmangalore
2026-05-14 18:39 ` Steve French
2026-05-14 18:08 ` [PATCH v5 04/17] cifs: optimize readdir for larger directories nspmangalore
2026-05-14 22:39 ` Steve French
2026-05-14 18:08 ` [PATCH v5 05/17] cifs: reorganize cached dir helpers nspmangalore
2026-05-14 18:08 ` [PATCH v5 06/17] cifs: make cfid locks more granular nspmangalore
2026-05-14 18:08 ` [PATCH v5 07/17] cifs: query dir should reuse cfid even if not fully cached nspmangalore
2026-05-14 18:08 ` [PATCH v5 08/17] cifs: back cached_dirents with page cache nspmangalore
2026-05-14 18:08 ` [PATCH v5 09/17] cifs: in place changes to cached_dirents when dir lease is held nspmangalore
2026-05-14 18:08 ` nspmangalore [this message]
2026-05-14 18:08 ` [PATCH v5 11/17] cifs: option to disable time-based eviction of cache nspmangalore
2026-05-14 18:08 ` [PATCH v5 12/17] cifs: option to set unlimited number of cached dirs nspmangalore
2026-05-14 18:08 ` [PATCH v5 13/17] cifs: allow dcache population to happen asynchronously nspmangalore
2026-05-14 18:08 ` [PATCH v5 14/17] cifs: trace points for cached_dir operations nspmangalore
2026-05-14 18:08 ` [PATCH v5 15/17] cifs: discard functions to ensure that mid callbacks get called nspmangalore
2026-05-14 18:08 ` [PATCH v5 16/17] cifs: keep cfids in rbtree for efficient lookups nspmangalore
2026-05-14 20:43 ` Enzo Matsumiya
2026-05-14 18:08 ` [PATCH v5 17/17] cifs: invalidate cached_dirents if population aborted nspmangalore
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260514180823.497293-10-sprasad@microsoft.com \
--to=nspmangalore@gmail.com \
--cc=bharathsm@microsoft.com \
--cc=dhowells@redhat.com \
--cc=ematsumiya@suse.de \
--cc=henrique.carvalho@suse.com \
--cc=linux-cifs@vger.kernel.org \
--cc=pc@manguebit.org \
--cc=smfrench@gmail.com \
--cc=sprasad@microsoft.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.