]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.0/smb3-allow-persistent-handle-timeout-to-be-configurable-on-mount.patch
Linux 4.19.35
[thirdparty/kernel/stable-queue.git] / queue-5.0 / smb3-allow-persistent-handle-timeout-to-be-configurable-on-mount.patch
1 From ca567eb2b3f014d5be0f44c6f68b01a522f15ca4 Mon Sep 17 00:00:00 2001
2 From: Steve French <stfrench@microsoft.com>
3 Date: Fri, 29 Mar 2019 16:31:07 -0500
4 Subject: SMB3: Allow persistent handle timeout to be configurable on mount
5
6 From: Steve French <stfrench@microsoft.com>
7
8 commit ca567eb2b3f014d5be0f44c6f68b01a522f15ca4 upstream.
9
10 Reconnecting after server or network failure can be improved
11 (to maintain availability and protect data integrity) by allowing
12 the client to choose the default persistent (or resilient)
13 handle timeout in some use cases. Today we default to 0 which lets
14 the server pick the default timeout (usually 120 seconds) but this
15 can be problematic for some workloads. Add the new mount parameter
16 to cifs.ko for SMB3 mounts "handletimeout" which enables the user
17 to override the default handle timeout for persistent (mount
18 option "persistenthandles") or resilient handles (mount option
19 "resilienthandles"). Maximum allowed is 16 minutes (960000 ms).
20 Units for the timeout are expressed in milliseconds. See
21 section 2.2.14.2.12 and 2.2.31.3 of the MS-SMB2 protocol
22 specification for more information.
23
24 Signed-off-by: Steve French <stfrench@microsoft.com>
25 Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
26 Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
27 CC: Stable <stable@vger.kernel.org>
28 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
29
30 ---
31 fs/cifs/cifsfs.c | 2 ++
32 fs/cifs/cifsglob.h | 8 ++++++++
33 fs/cifs/connect.c | 30 +++++++++++++++++++++++++++++-
34 fs/cifs/smb2file.c | 4 +++-
35 fs/cifs/smb2pdu.c | 14 +++++++++++---
36 5 files changed, 53 insertions(+), 5 deletions(-)
37
38 --- a/fs/cifs/cifsfs.c
39 +++ b/fs/cifs/cifsfs.c
40 @@ -559,6 +559,8 @@ cifs_show_options(struct seq_file *s, st
41 tcon->ses->server->echo_interval / HZ);
42 if (tcon->snapshot_time)
43 seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
44 + if (tcon->handle_timeout)
45 + seq_printf(s, ",handletimeout=%u", tcon->handle_timeout);
46 /* convert actimeo and display it in seconds */
47 seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
48
49 --- a/fs/cifs/cifsglob.h
50 +++ b/fs/cifs/cifsglob.h
51 @@ -60,6 +60,12 @@
52 #define CIFS_MAX_ACTIMEO (1 << 30)
53
54 /*
55 + * Max persistent and resilient handle timeout (milliseconds).
56 + * Windows durable max was 960000 (16 minutes)
57 + */
58 +#define SMB3_MAX_HANDLE_TIMEOUT 960000
59 +
60 +/*
61 * MAX_REQ is the maximum number of requests that WE will send
62 * on one socket concurrently.
63 */
64 @@ -572,6 +578,7 @@ struct smb_vol {
65 struct nls_table *local_nls;
66 unsigned int echo_interval; /* echo interval in secs */
67 __u64 snapshot_time; /* needed for timewarp tokens */
68 + __u32 handle_timeout; /* persistent and durable handle timeout in ms */
69 unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
70 };
71
72 @@ -1028,6 +1035,7 @@ struct cifs_tcon {
73 __u32 vol_serial_number;
74 __le64 vol_create_time;
75 __u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
76 + __u32 handle_timeout; /* persistent and durable handle timeout in ms */
77 __u32 ss_flags; /* sector size flags */
78 __u32 perf_sector_size; /* best sector size for perf */
79 __u32 max_chunks;
80 --- a/fs/cifs/connect.c
81 +++ b/fs/cifs/connect.c
82 @@ -103,7 +103,7 @@ enum {
83 Opt_cruid, Opt_gid, Opt_file_mode,
84 Opt_dirmode, Opt_port,
85 Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
86 - Opt_echo_interval, Opt_max_credits,
87 + Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
88 Opt_snapshot,
89
90 /* Mount options which take string value */
91 @@ -208,6 +208,7 @@ static const match_table_t cifs_mount_op
92 { Opt_rsize, "rsize=%s" },
93 { Opt_wsize, "wsize=%s" },
94 { Opt_actimeo, "actimeo=%s" },
95 + { Opt_handletimeout, "handletimeout=%s" },
96 { Opt_echo_interval, "echo_interval=%s" },
97 { Opt_max_credits, "max_credits=%s" },
98 { Opt_snapshot, "snapshot=%s" },
99 @@ -1600,6 +1601,9 @@ cifs_parse_mount_options(const char *mou
100
101 vol->actimeo = CIFS_DEF_ACTIMEO;
102
103 + /* Most clients set timeout to 0, allows server to use its default */
104 + vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
105 +
106 /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
107 vol->ops = &smb30_operations;
108 vol->vals = &smbdefault_values;
109 @@ -1998,6 +2002,18 @@ cifs_parse_mount_options(const char *mou
110 goto cifs_parse_mount_err;
111 }
112 break;
113 + case Opt_handletimeout:
114 + if (get_option_ul(args, &option)) {
115 + cifs_dbg(VFS, "%s: Invalid handletimeout value\n",
116 + __func__);
117 + goto cifs_parse_mount_err;
118 + }
119 + vol->handle_timeout = option;
120 + if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
121 + cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n");
122 + goto cifs_parse_mount_err;
123 + }
124 + break;
125 case Opt_echo_interval:
126 if (get_option_ul(args, &option)) {
127 cifs_dbg(VFS, "%s: Invalid echo interval value\n",
128 @@ -3164,6 +3180,8 @@ static int match_tcon(struct cifs_tcon *
129 return 0;
130 if (tcon->snapshot_time != volume_info->snapshot_time)
131 return 0;
132 + if (tcon->handle_timeout != volume_info->handle_timeout)
133 + return 0;
134 return 1;
135 }
136
137 @@ -3278,6 +3296,16 @@ cifs_get_tcon(struct cifs_ses *ses, stru
138 tcon->snapshot_time = volume_info->snapshot_time;
139 }
140
141 + if (volume_info->handle_timeout) {
142 + if (ses->server->vals->protocol_id == 0) {
143 + cifs_dbg(VFS,
144 + "Use SMB2.1 or later for handle timeout option\n");
145 + rc = -EOPNOTSUPP;
146 + goto out_fail;
147 + } else
148 + tcon->handle_timeout = volume_info->handle_timeout;
149 + }
150 +
151 tcon->ses = ses;
152 if (volume_info->password) {
153 tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
154 --- a/fs/cifs/smb2file.c
155 +++ b/fs/cifs/smb2file.c
156 @@ -68,7 +68,9 @@ smb2_open_file(const unsigned int xid, s
157
158
159 if (oparms->tcon->use_resilient) {
160 - nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
161 + /* default timeout is 0, servers pick default (120 seconds) */
162 + nr_ioctl_req.Timeout =
163 + cpu_to_le32(oparms->tcon->handle_timeout);
164 nr_ioctl_req.Reserved = 0;
165 rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
166 fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,
167 --- a/fs/cifs/smb2pdu.c
168 +++ b/fs/cifs/smb2pdu.c
169 @@ -1837,8 +1837,9 @@ add_lease_context(struct TCP_Server_Info
170 }
171
172 static struct create_durable_v2 *
173 -create_durable_v2_buf(struct cifs_fid *pfid)
174 +create_durable_v2_buf(struct cifs_open_parms *oparms)
175 {
176 + struct cifs_fid *pfid = oparms->fid;
177 struct create_durable_v2 *buf;
178
179 buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL);
180 @@ -1852,7 +1853,14 @@ create_durable_v2_buf(struct cifs_fid *p
181 (struct create_durable_v2, Name));
182 buf->ccontext.NameLength = cpu_to_le16(4);
183
184 - buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
185 + /*
186 + * NB: Handle timeout defaults to 0, which allows server to choose
187 + * (most servers default to 120 seconds) and most clients default to 0.
188 + * This can be overridden at mount ("handletimeout=") if the user wants
189 + * a different persistent (or resilient) handle timeout for all opens
190 + * opens on a particular SMB3 mount.
191 + */
192 + buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout);
193 buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
194 generate_random_uuid(buf->dcontext.CreateGuid);
195 memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
196 @@ -1905,7 +1913,7 @@ add_durable_v2_context(struct kvec *iov,
197 struct smb2_create_req *req = iov[0].iov_base;
198 unsigned int num = *num_iovec;
199
200 - iov[num].iov_base = create_durable_v2_buf(oparms->fid);
201 + iov[num].iov_base = create_durable_v2_buf(oparms);
202 if (iov[num].iov_base == NULL)
203 return -ENOMEM;
204 iov[num].iov_len = sizeof(struct create_durable_v2);