nfs and cifs on Linux currently have a mount parameter "actimeo" to control metadata (attribute) caching but cifs does not have additional mount parameters to allow distinguishing between caching directory metadata (e.g. needed to revalidate paths) and that for files. Add new mount parameter "acdirmax" to allow caching metadata for directories more loosely than file data. NFS adjusts metadata caching from acdirmin to acdirmax (and another two mount parms for files) but to reduce complexity, it is safer to just introduce the one mount parm to allow caching directories longer (30 seconds vs. the 1 second default for file metadata) which is still more conservative than other Linux filesystems (e.g. NFS sets acdirmax to 60 seconds) -- Thanks, Steve
From 505d2041479f568c4f4b9a170c484f866bc72c57 Mon Sep 17 00:00:00 2001 From: Steve French <stfrench@xxxxxxxxxxxxx> Date: Tue, 23 Feb 2021 15:50:57 -0600 Subject: [PATCH 1/2] cifs: Add new mount parameter "acdirmax" to allow caching directory metadata nfs and cifs on Linux currently have a mount parameter "actimeo" to control metadata (attribute) caching but cifs does not have additional mount parameters to allow distinguishing between caching directory metadata (e.g. needed to revalidate paths) and that for files. Add new mount parameter "acdirmax" to allow caching metadata for directories more loosely than file data. NFS adjusts metadata caching from acdirmin to acdirmax (and another two mount parms for files) but to reduce complexity, it is safer to just introduce the one mount parm to allow caching directories longer (30 seconds vs. the 1 second default for file metadata) which is still more conservative than other Linux filesystems (e.g. NFS sets acdirmax to 60 seconds) Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/cifsfs.c | 3 ++- fs/cifs/cifsglob.h | 8 +++++++- fs/cifs/connect.c | 2 ++ fs/cifs/fs_context.c | 9 +++++++++ fs/cifs/fs_context.h | 4 +++- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6f33ff3f625f..4e0b0b26e844 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -637,8 +637,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",snapshot=%llu", tcon->snapshot_time); if (tcon->handle_timeout) seq_printf(s, ",handletimeout=%u", tcon->handle_timeout); - /* convert actimeo and display it in seconds */ + /* convert actimeo and directory attribute timeout and display in seconds */ seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->actimeo / HZ); + seq_printf(s, ",acdirmax=%lu", cifs_sb->ctx->acdirmax / HZ); if (tcon->ses->chan_max > 1) seq_printf(s, ",multichannel,max_channels=%zu", diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3de3c5908a72..9a14f6f6ebd8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -50,11 +50,17 @@ #define CIFS_MIN_RCV_POOL 4 #define MAX_REOPEN_ATT 5 /* these many maximum attempts to reopen a file */ + /* - * default attribute cache timeout (jiffies) + * default attribute cache timeout for files (jiffies) */ #define CIFS_DEF_ACTIMEO (1 * HZ) +/* + * default attribute cache timeout for directories (jiffies) + */ +#define CIFS_DEF_ACDIRMAX (30 * HZ) + /* * max attribute cache timeout (jiffies) - 2^30 */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index cd6dbeaf2166..a9dc39aee9f4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2278,6 +2278,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) if (old->ctx->actimeo != new->ctx->actimeo) return 0; + if (old->ctx->acdirmax != new->ctx->acdirmax) + return 0; return 1; } diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 7d04f2255624..555969c8d586 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -140,6 +140,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_u32("rsize", Opt_rsize), fsparam_u32("wsize", Opt_wsize), fsparam_u32("actimeo", Opt_actimeo), + fsparam_u32("acdirmax", Opt_acdirmax), fsparam_u32("echo_interval", Opt_echo_interval), fsparam_u32("max_credits", Opt_max_credits), fsparam_u32("handletimeout", Opt_handletimeout), @@ -936,6 +937,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, goto cifs_parse_mount_err; } break; + case Opt_acdirmax: + ctx->acdirmax = HZ * result.uint_32; + if (ctx->acdirmax > CIFS_MAX_ACTIMEO) { + cifs_dbg(VFS, "acdirmax too large\n"); + goto cifs_parse_mount_err; + } + break; case Opt_echo_interval: ctx->echo_interval = result.uint_32; break; @@ -1362,6 +1370,7 @@ int smb3_init_fs_context(struct fs_context *fc) ctx->strict_io = true; ctx->actimeo = CIFS_DEF_ACTIMEO; + ctx->acdirmax = CIFS_DEF_ACDIRMAX; /* Most clients set timeout to 0, allows server to use its default */ ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 1c44a460e2c0..472372fec4e9 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -118,6 +118,7 @@ enum cifs_param { Opt_rsize, Opt_wsize, Opt_actimeo, + Opt_acdirmax, Opt_echo_interval, Opt_max_credits, Opt_snapshot, @@ -232,7 +233,8 @@ struct smb3_fs_context { unsigned int wsize; unsigned int min_offload; bool sockopt_tcp_nodelay:1; - unsigned long actimeo; /* attribute cache timeout (jiffies) */ + unsigned long actimeo; /* attribute cache timeout for files (jiffies) */ + unsigned long acdirmax; /* attribute cache timeout for directories (jiffies) */ struct smb_version_operations *ops; struct smb_version_values *vals; char *prepath; -- 2.27.0
From 79f731e14559be57d48647d22283b93600caf192 Mon Sep 17 00:00:00 2001 From: Steve French <stfrench@xxxxxxxxxxxxx> Date: Tue, 23 Feb 2021 16:16:09 -0600 Subject: [PATCH 2/2] cifs: convert revalidate of directories to using directory metadata cache timeout The new optional mount parm, "acdirmax" allows caching the metadata for a directory longer than file metadata, which can be very helpful for performance. Convert cifs_inode_needs_reval to check acdirmax for revalidating directory metadata (actimeo is checked for files) Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/inode.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a83b3a8ffaac..cfd31cc4520f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2198,12 +2198,23 @@ cifs_inode_needs_reval(struct inode *inode) if (!lookupCacheEnabled) return true; - if (!cifs_sb->ctx->actimeo) - return true; - - if (!time_in_range(jiffies, cifs_i->time, - cifs_i->time + cifs_sb->ctx->actimeo)) - return true; + /* + * depending on inode type, check if attribute caching disabled for + * files or directories + */ + if (S_ISDIR(inode->i_mode)) { + if (!cifs_sb->ctx->acdirmax) + return true; + if (!time_in_range(jiffies, cifs_i->time, + cifs_i->time + cifs_sb->ctx->acdirmax)) + return true; + } else { /* file */ + if (!cifs_sb->ctx->actimeo) + return true; + if (!time_in_range(jiffies, cifs_i->time, + cifs_i->time + cifs_sb->ctx->actimeo)) + return true; + } /* hardlinked files w/ noserverino get "special" treatment */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && -- 2.27.0