diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-11-13 02:36:04 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-28 14:05:32 -0400 |
commit | 3ab3f2a1fee45f5788ddccd8b3ece6f74ae905bd (patch) | |
tree | 62f186796729f2ead6c64734ad705c85987d850a | |
parent | 16c568efff82e4a6a75d2bd86576e648fad8a7fe (diff) |
cifs: quit playing games with draining iovecs
... and use ITER_BVEC for the page part of request to send
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/transport.c | 141 |
2 files changed, 41 insertions, 102 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d9b4f444fdf9..7d5f53a01922 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -37,8 +37,6 @@ extern void cifs_buf_release(void *); | |||
37 | extern struct smb_hdr *cifs_small_buf_get(void); | 37 | extern struct smb_hdr *cifs_small_buf_get(void); |
38 | extern void cifs_small_buf_release(void *); | 38 | extern void cifs_small_buf_release(void *); |
39 | extern void free_rsp_buf(int, void *); | 39 | extern void free_rsp_buf(int, void *); |
40 | extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, | ||
41 | struct kvec *iov); | ||
42 | extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, | 40 | extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, |
43 | unsigned int /* length */); | 41 | unsigned int /* length */); |
44 | extern unsigned int _get_xid(void); | 42 | extern unsigned int _get_xid(void); |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 87abe8ed074c..206a597b2293 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -124,41 +124,32 @@ cifs_delete_mid(struct mid_q_entry *mid) | |||
124 | /* | 124 | /* |
125 | * smb_send_kvec - send an array of kvecs to the server | 125 | * smb_send_kvec - send an array of kvecs to the server |
126 | * @server: Server to send the data to | 126 | * @server: Server to send the data to |
127 | * @iov: Pointer to array of kvecs | 127 | * @smb_msg: Message to send |
128 | * @n_vec: length of kvec array | ||
129 | * @sent: amount of data sent on socket is stored here | 128 | * @sent: amount of data sent on socket is stored here |
130 | * | 129 | * |
131 | * Our basic "send data to server" function. Should be called with srv_mutex | 130 | * Our basic "send data to server" function. Should be called with srv_mutex |
132 | * held. The caller is responsible for handling the results. | 131 | * held. The caller is responsible for handling the results. |
133 | */ | 132 | */ |
134 | static int | 133 | static int |
135 | smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | 134 | smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, |
136 | size_t *sent) | 135 | size_t *sent) |
137 | { | 136 | { |
138 | int rc = 0; | 137 | int rc = 0; |
139 | int i = 0; | 138 | int retries = 0; |
140 | struct msghdr smb_msg; | ||
141 | unsigned int remaining; | ||
142 | size_t first_vec = 0; | ||
143 | struct socket *ssocket = server->ssocket; | 139 | struct socket *ssocket = server->ssocket; |
144 | 140 | ||
145 | *sent = 0; | 141 | *sent = 0; |
146 | 142 | ||
147 | smb_msg.msg_name = (struct sockaddr *) &server->dstaddr; | 143 | smb_msg->msg_name = (struct sockaddr *) &server->dstaddr; |
148 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 144 | smb_msg->msg_namelen = sizeof(struct sockaddr); |
149 | smb_msg.msg_control = NULL; | 145 | smb_msg->msg_control = NULL; |
150 | smb_msg.msg_controllen = 0; | 146 | smb_msg->msg_controllen = 0; |
151 | if (server->noblocksnd) | 147 | if (server->noblocksnd) |
152 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; | 148 | smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; |
153 | else | 149 | else |
154 | smb_msg.msg_flags = MSG_NOSIGNAL; | 150 | smb_msg->msg_flags = MSG_NOSIGNAL; |
155 | |||
156 | remaining = 0; | ||
157 | for (i = 0; i < n_vec; i++) | ||
158 | remaining += iov[i].iov_len; | ||
159 | 151 | ||
160 | i = 0; | 152 | while (msg_data_left(smb_msg)) { |
161 | while (remaining) { | ||
162 | /* | 153 | /* |
163 | * If blocking send, we try 3 times, since each can block | 154 | * If blocking send, we try 3 times, since each can block |
164 | * for 5 seconds. For nonblocking we have to try more | 155 | * for 5 seconds. For nonblocking we have to try more |
@@ -177,35 +168,21 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | |||
177 | * after the retries we will kill the socket and | 168 | * after the retries we will kill the socket and |
178 | * reconnect which may clear the network problem. | 169 | * reconnect which may clear the network problem. |
179 | */ | 170 | */ |
180 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], | 171 | rc = sock_sendmsg(ssocket, smb_msg); |
181 | n_vec - first_vec, remaining); | ||
182 | if (rc == -EAGAIN) { | 172 | if (rc == -EAGAIN) { |
183 | i++; | 173 | retries++; |
184 | if (i >= 14 || (!server->noblocksnd && (i > 2))) { | 174 | if (retries >= 14 || |
175 | (!server->noblocksnd && (retries > 2))) { | ||
185 | cifs_dbg(VFS, "sends on sock %p stuck for 15 seconds\n", | 176 | cifs_dbg(VFS, "sends on sock %p stuck for 15 seconds\n", |
186 | ssocket); | 177 | ssocket); |
187 | rc = -EAGAIN; | 178 | return -EAGAIN; |
188 | break; | ||
189 | } | 179 | } |
190 | msleep(1 << i); | 180 | msleep(1 << retries); |
191 | continue; | 181 | continue; |
192 | } | 182 | } |
193 | 183 | ||
194 | if (rc < 0) | 184 | if (rc < 0) |
195 | break; | 185 | return rc; |
196 | |||
197 | /* send was at least partially successful */ | ||
198 | *sent += rc; | ||
199 | |||
200 | if (rc == remaining) { | ||
201 | remaining = 0; | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | if (rc > remaining) { | ||
206 | cifs_dbg(VFS, "sent %d requested %d\n", rc, remaining); | ||
207 | break; | ||
208 | } | ||
209 | 186 | ||
210 | if (rc == 0) { | 187 | if (rc == 0) { |
211 | /* should never happen, letting socket clear before | 188 | /* should never happen, letting socket clear before |
@@ -215,59 +192,11 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | |||
215 | continue; | 192 | continue; |
216 | } | 193 | } |
217 | 194 | ||
218 | remaining -= rc; | 195 | /* send was at least partially successful */ |
219 | 196 | *sent += rc; | |
220 | /* the line below resets i */ | 197 | retries = 0; /* in case we get ENOSPC on the next send */ |
221 | for (i = first_vec; i < n_vec; i++) { | ||
222 | if (iov[i].iov_len) { | ||
223 | if (rc > iov[i].iov_len) { | ||
224 | rc -= iov[i].iov_len; | ||
225 | iov[i].iov_len = 0; | ||
226 | } else { | ||
227 | iov[i].iov_base += rc; | ||
228 | iov[i].iov_len -= rc; | ||
229 | first_vec = i; | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | i = 0; /* in case we get ENOSPC on the next send */ | ||
236 | rc = 0; | ||
237 | } | 198 | } |
238 | return rc; | 199 | return 0; |
239 | } | ||
240 | |||
241 | /** | ||
242 | * rqst_page_to_kvec - Turn a slot in the smb_rqst page array into a kvec | ||
243 | * @rqst: pointer to smb_rqst | ||
244 | * @idx: index into the array of the page | ||
245 | * @iov: pointer to struct kvec that will hold the result | ||
246 | * | ||
247 | * Helper function to convert a slot in the rqst->rq_pages array into a kvec. | ||
248 | * The page will be kmapped and the address placed into iov_base. The length | ||
249 | * will then be adjusted according to the ptailoff. | ||
250 | */ | ||
251 | void | ||
252 | cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, | ||
253 | struct kvec *iov) | ||
254 | { | ||
255 | /* | ||
256 | * FIXME: We could avoid this kmap altogether if we used | ||
257 | * kernel_sendpage instead of kernel_sendmsg. That will only | ||
258 | * work if signing is disabled though as sendpage inlines the | ||
259 | * page directly into the fraglist. If userspace modifies the | ||
260 | * page after we calculate the signature, then the server will | ||
261 | * reject it and may break the connection. kernel_sendmsg does | ||
262 | * an extra copy of the data and avoids that issue. | ||
263 | */ | ||
264 | iov->iov_base = kmap(rqst->rq_pages[idx]); | ||
265 | |||
266 | /* if last page, don't send beyond this offset into page */ | ||
267 | if (idx == (rqst->rq_npages - 1)) | ||
268 | iov->iov_len = rqst->rq_tailsz; | ||
269 | else | ||
270 | iov->iov_len = rqst->rq_pagesz; | ||
271 | } | 200 | } |
272 | 201 | ||
273 | static unsigned long | 202 | static unsigned long |
@@ -299,8 +228,9 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
299 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); | 228 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); |
300 | unsigned long send_length; | 229 | unsigned long send_length; |
301 | unsigned int i; | 230 | unsigned int i; |
302 | size_t total_len = 0, sent; | 231 | size_t total_len = 0, sent, size; |
303 | struct socket *ssocket = server->ssocket; | 232 | struct socket *ssocket = server->ssocket; |
233 | struct msghdr smb_msg; | ||
304 | int val = 1; | 234 | int val = 1; |
305 | 235 | ||
306 | if (ssocket == NULL) | 236 | if (ssocket == NULL) |
@@ -321,7 +251,13 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
321 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, | 251 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |
322 | (char *)&val, sizeof(val)); | 252 | (char *)&val, sizeof(val)); |
323 | 253 | ||
324 | rc = smb_send_kvec(server, iov, n_vec, &sent); | 254 | size = 0; |
255 | for (i = 0; i < n_vec; i++) | ||
256 | size += iov[i].iov_len; | ||
257 | |||
258 | iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size); | ||
259 | |||
260 | rc = smb_send_kvec(server, &smb_msg, &sent); | ||
325 | if (rc < 0) | 261 | if (rc < 0) |
326 | goto uncork; | 262 | goto uncork; |
327 | 263 | ||
@@ -329,11 +265,16 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
329 | 265 | ||
330 | /* now walk the page array and send each page in it */ | 266 | /* now walk the page array and send each page in it */ |
331 | for (i = 0; i < rqst->rq_npages; i++) { | 267 | for (i = 0; i < rqst->rq_npages; i++) { |
332 | struct kvec p_iov; | 268 | size_t len = i == rqst->rq_npages - 1 |
333 | 269 | ? rqst->rq_tailsz | |
334 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | 270 | : rqst->rq_pagesz; |
335 | rc = smb_send_kvec(server, &p_iov, 1, &sent); | 271 | struct bio_vec bvec = { |
336 | kunmap(rqst->rq_pages[i]); | 272 | .bv_page = rqst->rq_pages[i], |
273 | .bv_len = len | ||
274 | }; | ||
275 | iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, | ||
276 | &bvec, 1, len); | ||
277 | rc = smb_send_kvec(server, &smb_msg, &sent); | ||
337 | if (rc < 0) | 278 | if (rc < 0) |
338 | break; | 279 | break; |
339 | 280 | ||