Skip to content

Commit ca567eb

Browse files
author
Steve French
committed
SMB3: Allow persistent handle timeout to be configurable on mount
Reconnecting after server or network failure can be improved (to maintain availability and protect data integrity) by allowing the client to choose the default persistent (or resilient) handle timeout in some use cases. Today we default to 0 which lets the server pick the default timeout (usually 120 seconds) but this can be problematic for some workloads. Add the new mount parameter to cifs.ko for SMB3 mounts "handletimeout" which enables the user to override the default handle timeout for persistent (mount option "persistenthandles") or resilient handles (mount option "resilienthandles"). Maximum allowed is 16 minutes (960000 ms). Units for the timeout are expressed in milliseconds. See section 2.2.14.2.12 and 2.2.31.3 of the MS-SMB2 protocol specification for more information. Signed-off-by: Steve French <[email protected]> Reviewed-by: Pavel Shilovsky <[email protected]> Reviewed-by: Ronnie Sahlberg <[email protected]> CC: Stable <[email protected]>
1 parent 153322f commit ca567eb

File tree

5 files changed

+53
-5
lines changed

5 files changed

+53
-5
lines changed

fs/cifs/cifsfs.c

+2
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
559559
tcon->ses->server->echo_interval / HZ);
560560
if (tcon->snapshot_time)
561561
seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
562+
if (tcon->handle_timeout)
563+
seq_printf(s, ",handletimeout=%u", tcon->handle_timeout);
562564
/* convert actimeo and display it in seconds */
563565
seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
564566

fs/cifs/cifsglob.h

+8
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@
5959
*/
6060
#define CIFS_MAX_ACTIMEO (1 << 30)
6161

62+
/*
63+
* Max persistent and resilient handle timeout (milliseconds).
64+
* Windows durable max was 960000 (16 minutes)
65+
*/
66+
#define SMB3_MAX_HANDLE_TIMEOUT 960000
67+
6268
/*
6369
* MAX_REQ is the maximum number of requests that WE will send
6470
* on one socket concurrently.
@@ -586,6 +592,7 @@ struct smb_vol {
586592
struct nls_table *local_nls;
587593
unsigned int echo_interval; /* echo interval in secs */
588594
__u64 snapshot_time; /* needed for timewarp tokens */
595+
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
589596
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
590597
};
591598

@@ -1058,6 +1065,7 @@ struct cifs_tcon {
10581065
__u32 vol_serial_number;
10591066
__le64 vol_create_time;
10601067
__u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
1068+
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
10611069
__u32 ss_flags; /* sector size flags */
10621070
__u32 perf_sector_size; /* best sector size for perf */
10631071
__u32 max_chunks;

fs/cifs/connect.c

+29-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ enum {
103103
Opt_cruid, Opt_gid, Opt_file_mode,
104104
Opt_dirmode, Opt_port,
105105
Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
106-
Opt_echo_interval, Opt_max_credits,
106+
Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
107107
Opt_snapshot,
108108

109109
/* Mount options which take string value */
@@ -208,6 +208,7 @@ static const match_table_t cifs_mount_option_tokens = {
208208
{ Opt_rsize, "rsize=%s" },
209209
{ Opt_wsize, "wsize=%s" },
210210
{ Opt_actimeo, "actimeo=%s" },
211+
{ Opt_handletimeout, "handletimeout=%s" },
211212
{ Opt_echo_interval, "echo_interval=%s" },
212213
{ Opt_max_credits, "max_credits=%s" },
213214
{ Opt_snapshot, "snapshot=%s" },
@@ -1619,6 +1620,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
16191620

16201621
vol->actimeo = CIFS_DEF_ACTIMEO;
16211622

1623+
/* Most clients set timeout to 0, allows server to use its default */
1624+
vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
1625+
16221626
/* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
16231627
vol->ops = &smb30_operations;
16241628
vol->vals = &smbdefault_values;
@@ -2017,6 +2021,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
20172021
goto cifs_parse_mount_err;
20182022
}
20192023
break;
2024+
case Opt_handletimeout:
2025+
if (get_option_ul(args, &option)) {
2026+
cifs_dbg(VFS, "%s: Invalid handletimeout value\n",
2027+
__func__);
2028+
goto cifs_parse_mount_err;
2029+
}
2030+
vol->handle_timeout = option;
2031+
if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
2032+
cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n");
2033+
goto cifs_parse_mount_err;
2034+
}
2035+
break;
20202036
case Opt_echo_interval:
20212037
if (get_option_ul(args, &option)) {
20222038
cifs_dbg(VFS, "%s: Invalid echo interval value\n",
@@ -3183,6 +3199,8 @@ static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
31833199
return 0;
31843200
if (tcon->snapshot_time != volume_info->snapshot_time)
31853201
return 0;
3202+
if (tcon->handle_timeout != volume_info->handle_timeout)
3203+
return 0;
31863204
return 1;
31873205
}
31883206

@@ -3297,6 +3315,16 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
32973315
tcon->snapshot_time = volume_info->snapshot_time;
32983316
}
32993317

3318+
if (volume_info->handle_timeout) {
3319+
if (ses->server->vals->protocol_id == 0) {
3320+
cifs_dbg(VFS,
3321+
"Use SMB2.1 or later for handle timeout option\n");
3322+
rc = -EOPNOTSUPP;
3323+
goto out_fail;
3324+
} else
3325+
tcon->handle_timeout = volume_info->handle_timeout;
3326+
}
3327+
33003328
tcon->ses = ses;
33013329
if (volume_info->password) {
33023330
tcon->password = kstrdup(volume_info->password, GFP_KERNEL);

fs/cifs/smb2file.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
6868

6969

7070
if (oparms->tcon->use_resilient) {
71-
nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
71+
/* default timeout is 0, servers pick default (120 seconds) */
72+
nr_ioctl_req.Timeout =
73+
cpu_to_le32(oparms->tcon->handle_timeout);
7274
nr_ioctl_req.Reserved = 0;
7375
rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
7476
fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,

fs/cifs/smb2pdu.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -1859,8 +1859,9 @@ add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
18591859
}
18601860

18611861
static struct create_durable_v2 *
1862-
create_durable_v2_buf(struct cifs_fid *pfid)
1862+
create_durable_v2_buf(struct cifs_open_parms *oparms)
18631863
{
1864+
struct cifs_fid *pfid = oparms->fid;
18641865
struct create_durable_v2 *buf;
18651866

18661867
buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL);
@@ -1874,7 +1875,14 @@ create_durable_v2_buf(struct cifs_fid *pfid)
18741875
(struct create_durable_v2, Name));
18751876
buf->ccontext.NameLength = cpu_to_le16(4);
18761877

1877-
buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
1878+
/*
1879+
* NB: Handle timeout defaults to 0, which allows server to choose
1880+
* (most servers default to 120 seconds) and most clients default to 0.
1881+
* This can be overridden at mount ("handletimeout=") if the user wants
1882+
* a different persistent (or resilient) handle timeout for all opens
1883+
* opens on a particular SMB3 mount.
1884+
*/
1885+
buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout);
18781886
buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
18791887
generate_random_uuid(buf->dcontext.CreateGuid);
18801888
memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
@@ -1927,7 +1935,7 @@ add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
19271935
struct smb2_create_req *req = iov[0].iov_base;
19281936
unsigned int num = *num_iovec;
19291937

1930-
iov[num].iov_base = create_durable_v2_buf(oparms->fid);
1938+
iov[num].iov_base = create_durable_v2_buf(oparms);
19311939
if (iov[num].iov_base == NULL)
19321940
return -ENOMEM;
19331941
iov[num].iov_len = sizeof(struct create_durable_v2);

0 commit comments

Comments
 (0)