]>
Commit | Line | Data |
---|---|---|
67307134 GKH |
1 | From 511c54a2f69195b28afb9dd119f03787b1625bb4 Mon Sep 17 00:00:00 2001 |
2 | From: Pavel Shilovsky <pshilov@microsoft.com> | |
3 | Date: Sat, 8 Jul 2017 14:32:00 -0700 | |
4 | Subject: CIFS: Reconnect expired SMB sessions | |
5 | ||
6 | From: Pavel Shilovsky <pshilov@microsoft.com> | |
7 | ||
8 | commit 511c54a2f69195b28afb9dd119f03787b1625bb4 upstream. | |
9 | ||
10 | According to the MS-SMB2 spec (3.2.5.1.6) once the client receives | |
11 | STATUS_NETWORK_SESSION_EXPIRED error code from a server it should | |
12 | reconnect the current SMB session. Currently the client doesn't do | |
13 | that. This can result in subsequent client requests failing by | |
14 | the server. The patch adds an additional logic to the demultiplex | |
15 | thread to identify expired sessions and reconnect them. | |
16 | ||
17 | Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> | |
18 | Signed-off-by: Steve French <smfrench@gmail.com> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
20 | ||
21 | --- | |
22 | fs/cifs/cifsglob.h | 2 ++ | |
23 | fs/cifs/cifssmb.c | 7 +++++++ | |
24 | fs/cifs/connect.c | 7 +++++++ | |
25 | fs/cifs/smb2ops.c | 16 ++++++++++++++++ | |
26 | 4 files changed, 32 insertions(+) | |
27 | ||
28 | --- a/fs/cifs/cifsglob.h | |
29 | +++ b/fs/cifs/cifsglob.h | |
30 | @@ -351,6 +351,8 @@ struct smb_version_operations { | |
31 | unsigned int (*calc_smb_size)(void *); | |
32 | /* check for STATUS_PENDING and process it in a positive case */ | |
33 | bool (*is_status_pending)(char *, struct TCP_Server_Info *, int); | |
34 | + /* check for STATUS_NETWORK_SESSION_EXPIRED */ | |
35 | + bool (*is_session_expired)(char *); | |
36 | /* send oplock break response */ | |
37 | int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *, | |
38 | struct cifsInodeInfo *); | |
39 | --- a/fs/cifs/cifssmb.c | |
40 | +++ b/fs/cifs/cifssmb.c | |
41 | @@ -1460,6 +1460,13 @@ cifs_readv_receive(struct TCP_Server_Inf | |
42 | return length; | |
43 | server->total_read += length; | |
44 | ||
45 | + if (server->ops->is_session_expired && | |
46 | + server->ops->is_session_expired(buf)) { | |
47 | + cifs_reconnect(server); | |
48 | + wake_up(&server->response_q); | |
49 | + return -1; | |
50 | + } | |
51 | + | |
52 | if (server->ops->is_status_pending && | |
53 | server->ops->is_status_pending(buf, server, 0)) { | |
54 | discard_remaining_data(server); | |
55 | --- a/fs/cifs/connect.c | |
56 | +++ b/fs/cifs/connect.c | |
57 | @@ -850,6 +850,13 @@ standard_receive3(struct TCP_Server_Info | |
58 | cifs_dump_mem("Bad SMB: ", buf, | |
59 | min_t(unsigned int, server->total_read, 48)); | |
60 | ||
61 | + if (server->ops->is_session_expired && | |
62 | + server->ops->is_session_expired(buf)) { | |
63 | + cifs_reconnect(server); | |
64 | + wake_up(&server->response_q); | |
65 | + return -1; | |
66 | + } | |
67 | + | |
68 | if (server->ops->is_status_pending && | |
69 | server->ops->is_status_pending(buf, server, length)) | |
70 | return -1; | |
71 | --- a/fs/cifs/smb2ops.c | |
72 | +++ b/fs/cifs/smb2ops.c | |
73 | @@ -963,6 +963,18 @@ smb2_is_status_pending(char *buf, struct | |
74 | return true; | |
75 | } | |
76 | ||
77 | +static bool | |
78 | +smb2_is_session_expired(char *buf) | |
79 | +{ | |
80 | + struct smb2_hdr *hdr = (struct smb2_hdr *)buf; | |
81 | + | |
82 | + if (hdr->Status != STATUS_NETWORK_SESSION_EXPIRED) | |
83 | + return false; | |
84 | + | |
85 | + cifs_dbg(FYI, "Session expired\n"); | |
86 | + return true; | |
87 | +} | |
88 | + | |
89 | static int | |
90 | smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, | |
91 | struct cifsInodeInfo *cinode) | |
92 | @@ -1552,6 +1564,7 @@ struct smb_version_operations smb20_oper | |
93 | .close_dir = smb2_close_dir, | |
94 | .calc_smb_size = smb2_calc_size, | |
95 | .is_status_pending = smb2_is_status_pending, | |
96 | + .is_session_expired = smb2_is_session_expired, | |
97 | .oplock_response = smb2_oplock_response, | |
98 | .queryfs = smb2_queryfs, | |
99 | .mand_lock = smb2_mand_lock, | |
100 | @@ -1633,6 +1646,7 @@ struct smb_version_operations smb21_oper | |
101 | .close_dir = smb2_close_dir, | |
102 | .calc_smb_size = smb2_calc_size, | |
103 | .is_status_pending = smb2_is_status_pending, | |
104 | + .is_session_expired = smb2_is_session_expired, | |
105 | .oplock_response = smb2_oplock_response, | |
106 | .queryfs = smb2_queryfs, | |
107 | .mand_lock = smb2_mand_lock, | |
108 | @@ -1715,6 +1729,7 @@ struct smb_version_operations smb30_oper | |
109 | .close_dir = smb2_close_dir, | |
110 | .calc_smb_size = smb2_calc_size, | |
111 | .is_status_pending = smb2_is_status_pending, | |
112 | + .is_session_expired = smb2_is_session_expired, | |
113 | .oplock_response = smb2_oplock_response, | |
114 | .queryfs = smb2_queryfs, | |
115 | .mand_lock = smb2_mand_lock, | |
116 | @@ -1803,6 +1818,7 @@ struct smb_version_operations smb311_ope | |
117 | .close_dir = smb2_close_dir, | |
118 | .calc_smb_size = smb2_calc_size, | |
119 | .is_status_pending = smb2_is_status_pending, | |
120 | + .is_session_expired = smb2_is_session_expired, | |
121 | .oplock_response = smb2_oplock_response, | |
122 | .queryfs = smb2_queryfs, | |
123 | .mand_lock = smb2_mand_lock, |