aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2015-11-13 02:36:04 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2016-03-28 14:05:32 -0400
commit3ab3f2a1fee45f5788ddccd8b3ece6f74ae905bd (patch)
tree62f186796729f2ead6c64734ad705c85987d850a
parent16c568efff82e4a6a75d2bd86576e648fad8a7fe (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.h2
-rw-r--r--fs/cifs/transport.c141
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 *);
37extern struct smb_hdr *cifs_small_buf_get(void); 37extern struct smb_hdr *cifs_small_buf_get(void);
38extern void cifs_small_buf_release(void *); 38extern void cifs_small_buf_release(void *);
39extern void free_rsp_buf(int, void *); 39extern void free_rsp_buf(int, void *);
40extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
41 struct kvec *iov);
42extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, 40extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
43 unsigned int /* length */); 41 unsigned int /* length */);
44extern unsigned int _get_xid(void); 42extern 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 */
134static int 133static int
135smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, 134smb_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 */
251void
252cifs_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
273static unsigned long 202static 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