]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.19.31/cifs-do-not-skip-smb2-message-ids-on-send-failures.patch
Linux 4.19.31
[thirdparty/kernel/stable-queue.git] / releases / 4.19.31 / cifs-do-not-skip-smb2-message-ids-on-send-failures.patch
1 From c781af7e0c1fed9f1d0e0ec31b86f5b21a8dca17 Mon Sep 17 00:00:00 2001
2 From: Pavel Shilovsky <piastryyy@gmail.com>
3 Date: Mon, 4 Mar 2019 14:02:50 -0800
4 Subject: CIFS: Do not skip SMB2 message IDs on send failures
5
6 From: Pavel Shilovsky <piastryyy@gmail.com>
7
8 commit c781af7e0c1fed9f1d0e0ec31b86f5b21a8dca17 upstream.
9
10 When we hit failures during constructing MIDs or sending PDUs
11 through the network, we end up not using message IDs assigned
12 to the packet. The next SMB packet will skip those message IDs
13 and continue with the next one. This behavior may lead to a server
14 not granting us credits until we use the skipped IDs. Fix this by
15 reverting the current ID to the original value if any errors occur
16 before we push the packet through the network stack.
17
18 This patch fixes the generic/310 test from the xfs-tests.
19
20 Cc: <stable@vger.kernel.org> # 4.19.x
21 Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
22 Signed-off-by: Steve French <stfrench@microsoft.com>
23 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
24
25 ---
26 fs/cifs/cifsglob.h | 19 +++++++++++++++++++
27 fs/cifs/smb2ops.c | 13 +++++++++++++
28 fs/cifs/smb2transport.c | 14 ++++++++++++--
29 fs/cifs/transport.c | 6 +++++-
30 4 files changed, 49 insertions(+), 3 deletions(-)
31
32 --- a/fs/cifs/cifsglob.h
33 +++ b/fs/cifs/cifsglob.h
34 @@ -235,6 +235,8 @@ struct smb_version_operations {
35 int * (*get_credits_field)(struct TCP_Server_Info *, const int);
36 unsigned int (*get_credits)(struct mid_q_entry *);
37 __u64 (*get_next_mid)(struct TCP_Server_Info *);
38 + void (*revert_current_mid)(struct TCP_Server_Info *server,
39 + const unsigned int val);
40 /* data offset from read response message */
41 unsigned int (*read_data_offset)(char *);
42 /*
43 @@ -756,6 +758,22 @@ get_next_mid(struct TCP_Server_Info *ser
44 return cpu_to_le16(mid);
45 }
46
47 +static inline void
48 +revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
49 +{
50 + if (server->ops->revert_current_mid)
51 + server->ops->revert_current_mid(server, val);
52 +}
53 +
54 +static inline void
55 +revert_current_mid_from_hdr(struct TCP_Server_Info *server,
56 + const struct smb2_sync_hdr *shdr)
57 +{
58 + unsigned int num = le16_to_cpu(shdr->CreditCharge);
59 +
60 + return revert_current_mid(server, num > 0 ? num : 1);
61 +}
62 +
63 static inline __u16
64 get_mid(const struct smb_hdr *smb)
65 {
66 @@ -1391,6 +1409,7 @@ struct mid_q_entry {
67 struct kref refcount;
68 struct TCP_Server_Info *server; /* server corresponding to this mid */
69 __u64 mid; /* multiplex id */
70 + __u16 credits; /* number of credits consumed by this mid */
71 __u32 pid; /* process id */
72 __u32 sequence_number; /* for CIFS signing */
73 unsigned long when_alloc; /* when mid was created */
74 --- a/fs/cifs/smb2ops.c
75 +++ b/fs/cifs/smb2ops.c
76 @@ -204,6 +204,15 @@ smb2_get_next_mid(struct TCP_Server_Info
77 return mid;
78 }
79
80 +static void
81 +smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
82 +{
83 + spin_lock(&GlobalMid_Lock);
84 + if (server->CurrentMid >= val)
85 + server->CurrentMid -= val;
86 + spin_unlock(&GlobalMid_Lock);
87 +}
88 +
89 static struct mid_q_entry *
90 smb2_find_mid(struct TCP_Server_Info *server, char *buf)
91 {
92 @@ -3256,6 +3265,7 @@ struct smb_version_operations smb20_oper
93 .get_credits = smb2_get_credits,
94 .wait_mtu_credits = cifs_wait_mtu_credits,
95 .get_next_mid = smb2_get_next_mid,
96 + .revert_current_mid = smb2_revert_current_mid,
97 .read_data_offset = smb2_read_data_offset,
98 .read_data_length = smb2_read_data_length,
99 .map_error = map_smb2_to_linux_error,
100 @@ -3350,6 +3360,7 @@ struct smb_version_operations smb21_oper
101 .get_credits = smb2_get_credits,
102 .wait_mtu_credits = smb2_wait_mtu_credits,
103 .get_next_mid = smb2_get_next_mid,
104 + .revert_current_mid = smb2_revert_current_mid,
105 .read_data_offset = smb2_read_data_offset,
106 .read_data_length = smb2_read_data_length,
107 .map_error = map_smb2_to_linux_error,
108 @@ -3445,6 +3456,7 @@ struct smb_version_operations smb30_oper
109 .get_credits = smb2_get_credits,
110 .wait_mtu_credits = smb2_wait_mtu_credits,
111 .get_next_mid = smb2_get_next_mid,
112 + .revert_current_mid = smb2_revert_current_mid,
113 .read_data_offset = smb2_read_data_offset,
114 .read_data_length = smb2_read_data_length,
115 .map_error = map_smb2_to_linux_error,
116 @@ -3549,6 +3561,7 @@ struct smb_version_operations smb311_ope
117 .get_credits = smb2_get_credits,
118 .wait_mtu_credits = smb2_wait_mtu_credits,
119 .get_next_mid = smb2_get_next_mid,
120 + .revert_current_mid = smb2_revert_current_mid,
121 .read_data_offset = smb2_read_data_offset,
122 .read_data_length = smb2_read_data_length,
123 .map_error = map_smb2_to_linux_error,
124 --- a/fs/cifs/smb2transport.c
125 +++ b/fs/cifs/smb2transport.c
126 @@ -576,6 +576,7 @@ smb2_mid_entry_alloc(const struct smb2_s
127 struct TCP_Server_Info *server)
128 {
129 struct mid_q_entry *temp;
130 + unsigned int credits = le16_to_cpu(shdr->CreditCharge);
131
132 if (server == NULL) {
133 cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n");
134 @@ -586,6 +587,7 @@ smb2_mid_entry_alloc(const struct smb2_s
135 memset(temp, 0, sizeof(struct mid_q_entry));
136 kref_init(&temp->refcount);
137 temp->mid = le64_to_cpu(shdr->MessageId);
138 + temp->credits = credits > 0 ? credits : 1;
139 temp->pid = current->pid;
140 temp->command = shdr->Command; /* Always LE */
141 temp->when_alloc = jiffies;
142 @@ -674,13 +676,18 @@ smb2_setup_request(struct cifs_ses *ses,
143 smb2_seq_num_into_buf(ses->server, shdr);
144
145 rc = smb2_get_mid_entry(ses, shdr, &mid);
146 - if (rc)
147 + if (rc) {
148 + revert_current_mid_from_hdr(ses->server, shdr);
149 return ERR_PTR(rc);
150 + }
151 +
152 rc = smb2_sign_rqst(rqst, ses->server);
153 if (rc) {
154 + revert_current_mid_from_hdr(ses->server, shdr);
155 cifs_delete_mid(mid);
156 return ERR_PTR(rc);
157 }
158 +
159 return mid;
160 }
161
162 @@ -695,11 +702,14 @@ smb2_setup_async_request(struct TCP_Serv
163 smb2_seq_num_into_buf(server, shdr);
164
165 mid = smb2_mid_entry_alloc(shdr, server);
166 - if (mid == NULL)
167 + if (mid == NULL) {
168 + revert_current_mid_from_hdr(server, shdr);
169 return ERR_PTR(-ENOMEM);
170 + }
171
172 rc = smb2_sign_rqst(rqst, server);
173 if (rc) {
174 + revert_current_mid_from_hdr(server, shdr);
175 DeleteMidQEntry(mid);
176 return ERR_PTR(rc);
177 }
178 --- a/fs/cifs/transport.c
179 +++ b/fs/cifs/transport.c
180 @@ -638,6 +638,7 @@ cifs_call_async(struct TCP_Server_Info *
181 cifs_in_send_dec(server);
182
183 if (rc < 0) {
184 + revert_current_mid(server, mid->credits);
185 server->sequence_number -= 2;
186 cifs_delete_mid(mid);
187 }
188 @@ -842,6 +843,7 @@ compound_send_recv(const unsigned int xi
189 for (i = 0; i < num_rqst; i++) {
190 midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]);
191 if (IS_ERR(midQ[i])) {
192 + revert_current_mid(ses->server, i);
193 for (j = 0; j < i; j++)
194 cifs_delete_mid(midQ[j]);
195 mutex_unlock(&ses->server->srv_mutex);
196 @@ -867,8 +869,10 @@ compound_send_recv(const unsigned int xi
197 for (i = 0; i < num_rqst; i++)
198 cifs_save_when_sent(midQ[i]);
199
200 - if (rc < 0)
201 + if (rc < 0) {
202 + revert_current_mid(ses->server, num_rqst);
203 ses->server->sequence_number -= 2;
204 + }
205
206 mutex_unlock(&ses->server->srv_mutex);
207