| From: Steve French <stfrench@microsoft.com> |
| Date: Thu, 11 Aug 2022 00:53:00 -0500 |
| Subject: [PATCH] smb3: allow deferred close timeout to be configurable |
| Git-commit: 5efdd9122eff772eae2feae9f0fc0ec02d4846a3 |
| References: bsc#1193629 |
| Patch-mainline: v6.0-rc1 |
| |
| Deferred close can be a very useful feature for allowing |
| caching data for read, and for minimizing the number of |
| reopens needed for a file that is repeatedly opened and |
| close but there are workloads where its default (1 second, |
| similar to actimeo/acregmax) is much too small. |
| |
| Allow the user to configure the amount of time we can |
| defer sending the final smb3 close when we have a |
| handle lease on the file (rather than forcing it to depend |
| on value of actimeo which is often unrelated, and less safe). |
| |
| Adds new mount parameter "closetimeo=" which is the maximum |
| number of seconds we can wait before sending an SMB3 |
| close when we have a handle lease for it. Default value |
| also is set to slightly larger at 5 seconds (although some |
| other clients use larger default this should still help). |
| |
| Suggested-by: Bharath SM <bharathsm@microsoft.com> |
| Reviewed-by: Bharath SM <bharathsm@microsoft.com> |
| Reviewed-by: Shyam Prasad N <sprasad@microsoft.com> |
| Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz> |
| Signed-off-by: Steve French <stfrench@microsoft.com> |
| Acked-by: Paulo Alcantara <palcantara@suse.de> |
| |
| fs/cifs/cifsfs.c | 1 + |
| fs/cifs/connect.c | 2 ++ |
| fs/cifs/file.c | 4 ++-- |
| fs/cifs/fs_context.c | 9 +++++++++ |
| fs/cifs/fs_context.h | 8 ++++++++ |
| 5 files changed, 22 insertions(+), 2 deletions(-) |
| |
| diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c |
| index 945fb083cea7..f54d8bf2732a 100644 |
| |
| |
| @@ -693,6 +693,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) |
| seq_printf(s, ",acdirmax=%lu", cifs_sb->ctx->acdirmax / HZ); |
| seq_printf(s, ",acregmax=%lu", cifs_sb->ctx->acregmax / HZ); |
| } |
| + seq_printf(s, ",closetimeo=%lu", cifs_sb->ctx->closetimeo / HZ); |
| |
| if (tcon->ses->chan_max > 1) |
| seq_printf(s, ",multichannel,max_channels=%zu", |
| diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c |
| index 7f205a9a2de4..9111c025bcb8 100644 |
| |
| |
| @@ -2681,6 +2681,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) |
| return 0; |
| if (old->ctx->acdirmax != new->ctx->acdirmax) |
| return 0; |
| + if (old->ctx->closetimeo != new->ctx->closetimeo) |
| + return 0; |
| |
| return 1; |
| } |
| diff --git a/fs/cifs/file.c b/fs/cifs/file.c |
| index 42f2639a1a66..2c5eae7d31f4 100644 |
| |
| |
| @@ -964,12 +964,12 @@ int cifs_close(struct inode *inode, struct file *file) |
| * So, Increase the ref count to avoid use-after-free. |
| */ |
| if (!mod_delayed_work(deferredclose_wq, |
| - &cfile->deferred, cifs_sb->ctx->acregmax)) |
| + &cfile->deferred, cifs_sb->ctx->closetimeo)) |
| cifsFileInfo_get(cfile); |
| } else { |
| /* Deferred close for files */ |
| queue_delayed_work(deferredclose_wq, |
| - &cfile->deferred, cifs_sb->ctx->acregmax); |
| + &cfile->deferred, cifs_sb->ctx->closetimeo); |
| cfile->deferred_close_scheduled = true; |
| spin_unlock(&cinode->deferred_lock); |
| return 0; |
| diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c |
| index 8dc0d923ef6a..0e13dec86b25 100644 |
| |
| |
| @@ -147,6 +147,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { |
| fsparam_u32("actimeo", Opt_actimeo), |
| fsparam_u32("acdirmax", Opt_acdirmax), |
| fsparam_u32("acregmax", Opt_acregmax), |
| + fsparam_u32("closetimeo", Opt_closetimeo), |
| fsparam_u32("echo_interval", Opt_echo_interval), |
| fsparam_u32("max_credits", Opt_max_credits), |
| fsparam_u32("handletimeout", Opt_handletimeout), |
| @@ -1074,6 +1075,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, |
| } |
| ctx->acdirmax = ctx->acregmax = HZ * result.uint_32; |
| break; |
| + case Opt_closetimeo: |
| + ctx->closetimeo = HZ * result.uint_32; |
| + if (ctx->closetimeo > SMB3_MAX_DCLOSETIMEO) { |
| + cifs_errorf(fc, "closetimeo too large\n"); |
| + goto cifs_parse_mount_err; |
| + } |
| + break; |
| case Opt_echo_interval: |
| ctx->echo_interval = result.uint_32; |
| break; |
| @@ -1521,6 +1529,7 @@ int smb3_init_fs_context(struct fs_context *fc) |
| |
| ctx->acregmax = CIFS_DEF_ACTIMEO; |
| ctx->acdirmax = CIFS_DEF_ACTIMEO; |
| + ctx->closetimeo = SMB3_DEF_DCLOSETIMEO; |
| |
| /* 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 5f093cb7e9b9..bbaee4c2281f 100644 |
| |
| |
| @@ -125,6 +125,7 @@ enum cifs_param { |
| Opt_actimeo, |
| Opt_acdirmax, |
| Opt_acregmax, |
| + Opt_closetimeo, |
| Opt_echo_interval, |
| Opt_max_credits, |
| Opt_snapshot, |
| @@ -247,6 +248,8 @@ struct smb3_fs_context { |
| /* attribute cache timemout for files and directories in jiffies */ |
| unsigned long acregmax; |
| unsigned long acdirmax; |
| + /* timeout for deferred close of files in jiffies */ |
| + unsigned long closetimeo; |
| struct smb_version_operations *ops; |
| struct smb_version_values *vals; |
| char *prepath; |
| @@ -279,4 +282,9 @@ static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *f |
| extern int smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx); |
| extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb); |
| |
| +/* |
| + * max deferred close timeout (jiffies) - 2^30 |
| + */ |
| +#define SMB3_MAX_DCLOSETIMEO (1 << 30) |
| +#define SMB3_DEF_DCLOSETIMEO (5 * HZ) /* Can increase later, other clients use larger */ |
| #endif |
| -- |
| 2.38.0 |
| |
| |