149 lines
4.8 KiB
Diff
149 lines
4.8 KiB
Diff
From 17457c5d0fa0b98cef9d2236a1518b1ded25fa5d Mon Sep 17 00:00:00 2001
|
|
From: Bharath SM <bharathsm.hsk@gmail.com>
|
|
Date: Wed, 11 Jun 2025 16:59:02 +0530
|
|
Subject: smb: improve directory cache reuse for readdir operations
|
|
|
|
Currently, cached directory contents were not reused across subsequent
|
|
'ls' operations because the cache validity check relied on comparing
|
|
the ctx pointer, which changes with each readdir invocation. As a
|
|
result, the cached dir entries was not marked as valid and the cache was
|
|
not utilized for subsequent 'ls' operations.
|
|
|
|
This change uses the file pointer, which remains consistent across all
|
|
readdir calls for a given directory instance, to associate and validate
|
|
the cache. As a result, cached directory contents can now be
|
|
correctly reused, improving performance for repeated directory listings.
|
|
|
|
Performance gains with local windows SMB server:
|
|
|
|
Without the patch and default actimeo=1:
|
|
1000 directory enumeration operations on dir with 10k files took 135.0s
|
|
|
|
With this patch and actimeo=0:
|
|
1000 directory enumeration operations on dir with 10k files took just 5.1s
|
|
|
|
Signed-off-by: Bharath SM <bharathsm@microsoft.com>
|
|
Reviewed-by: Shyam Prasad N <sprasad@microsoft.com>
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
---
|
|
fs/smb/client/cached_dir.h | 8 ++++----
|
|
fs/smb/client/readdir.c | 28 +++++++++++++++-------------
|
|
2 files changed, 19 insertions(+), 17 deletions(-)
|
|
|
|
--- a/fs/smb/client/cached_dir.h
|
|
+++ b/fs/smb/client/cached_dir.h
|
|
@@ -21,10 +21,10 @@ struct cached_dirent {
|
|
struct cached_dirents {
|
|
bool is_valid:1;
|
|
bool is_failed:1;
|
|
- struct dir_context *ctx; /*
|
|
- * Only used to make sure we only take entries
|
|
- * from a single context. Never dereferenced.
|
|
- */
|
|
+ struct file *file; /*
|
|
+ * Used to associate the cache with a single
|
|
+ * open file instance.
|
|
+ */
|
|
struct mutex de_mutex;
|
|
int pos; /* Expected ctx->pos */
|
|
struct list_head entries;
|
|
--- a/fs/smb/client/readdir.c
|
|
+++ b/fs/smb/client/readdir.c
|
|
@@ -850,9 +850,9 @@ static bool emit_cached_dirents(struct c
|
|
}
|
|
|
|
static void update_cached_dirents_count(struct cached_dirents *cde,
|
|
- struct dir_context *ctx)
|
|
+ struct file *file)
|
|
{
|
|
- if (cde->ctx != ctx)
|
|
+ if (cde->file != file)
|
|
return;
|
|
if (cde->is_valid || cde->is_failed)
|
|
return;
|
|
@@ -861,9 +861,9 @@ static void update_cached_dirents_count(
|
|
}
|
|
|
|
static void finished_cached_dirents_count(struct cached_dirents *cde,
|
|
- struct dir_context *ctx)
|
|
+ struct dir_context *ctx, struct file *file)
|
|
{
|
|
- if (cde->ctx != ctx)
|
|
+ if (cde->file != file)
|
|
return;
|
|
if (cde->is_valid || cde->is_failed)
|
|
return;
|
|
@@ -876,11 +876,12 @@ static void finished_cached_dirents_coun
|
|
static void add_cached_dirent(struct cached_dirents *cde,
|
|
struct dir_context *ctx,
|
|
const char *name, int namelen,
|
|
- struct cifs_fattr *fattr)
|
|
+ struct cifs_fattr *fattr,
|
|
+ struct file *file)
|
|
{
|
|
struct cached_dirent *de;
|
|
|
|
- if (cde->ctx != ctx)
|
|
+ if (cde->file != file)
|
|
return;
|
|
if (cde->is_valid || cde->is_failed)
|
|
return;
|
|
@@ -910,7 +911,8 @@ static void add_cached_dirent(struct cac
|
|
static bool cifs_dir_emit(struct dir_context *ctx,
|
|
const char *name, int namelen,
|
|
struct cifs_fattr *fattr,
|
|
- struct cached_fid *cfid)
|
|
+ struct cached_fid *cfid,
|
|
+ struct file *file)
|
|
{
|
|
bool rc;
|
|
ino_t ino = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
|
|
@@ -922,7 +924,7 @@ static bool cifs_dir_emit(struct dir_con
|
|
if (cfid) {
|
|
mutex_lock(&cfid->dirents.de_mutex);
|
|
add_cached_dirent(&cfid->dirents, ctx, name, namelen,
|
|
- fattr);
|
|
+ fattr, file);
|
|
mutex_unlock(&cfid->dirents.de_mutex);
|
|
}
|
|
|
|
@@ -1022,7 +1024,7 @@ static int cifs_filldir(char *find_entry
|
|
cifs_prime_dcache(file_dentry(file), &name, &fattr);
|
|
|
|
return !cifs_dir_emit(ctx, name.name, name.len,
|
|
- &fattr, cfid);
|
|
+ &fattr, cfid, file);
|
|
}
|
|
|
|
|
|
@@ -1073,8 +1075,8 @@ int cifs_readdir(struct file *file, stru
|
|
* we need to initialize scanning and storing the
|
|
* directory content.
|
|
*/
|
|
- if (ctx->pos == 0 && cfid->dirents.ctx == NULL) {
|
|
- cfid->dirents.ctx = ctx;
|
|
+ if (ctx->pos == 0 && cfid->dirents.file == NULL) {
|
|
+ cfid->dirents.file = file;
|
|
cfid->dirents.pos = 2;
|
|
}
|
|
/*
|
|
@@ -1142,7 +1144,7 @@ int cifs_readdir(struct file *file, stru
|
|
} else {
|
|
if (cfid) {
|
|
mutex_lock(&cfid->dirents.de_mutex);
|
|
- finished_cached_dirents_count(&cfid->dirents, ctx);
|
|
+ finished_cached_dirents_count(&cfid->dirents, ctx, file);
|
|
mutex_unlock(&cfid->dirents.de_mutex);
|
|
}
|
|
cifs_dbg(FYI, "Could not find entry\n");
|
|
@@ -1183,7 +1185,7 @@ int cifs_readdir(struct file *file, stru
|
|
ctx->pos++;
|
|
if (cfid) {
|
|
mutex_lock(&cfid->dirents.de_mutex);
|
|
- update_cached_dirents_count(&cfid->dirents, ctx);
|
|
+ update_cached_dirents_count(&cfid->dirents, file);
|
|
mutex_unlock(&cfid->dirents.de_mutex);
|
|
}
|
|
|