diff options
Diffstat (limited to 'net/9p/trans_virtio.c')
-rw-r--r-- | net/9p/trans_virtio.c | 48 |
1 files changed, 39 insertions, 9 deletions
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index de2e950a0a7a..e1c26b101830 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -194,11 +194,14 @@ static int pack_sg_list(struct scatterlist *sg, int start, | |||
194 | if (s > count) | 194 | if (s > count) |
195 | s = count; | 195 | s = count; |
196 | BUG_ON(index > limit); | 196 | BUG_ON(index > limit); |
197 | /* Make sure we don't terminate early. */ | ||
198 | sg_unmark_end(&sg[index]); | ||
197 | sg_set_buf(&sg[index++], data, s); | 199 | sg_set_buf(&sg[index++], data, s); |
198 | count -= s; | 200 | count -= s; |
199 | data += s; | 201 | data += s; |
200 | } | 202 | } |
201 | 203 | if (index-start) | |
204 | sg_mark_end(&sg[index - 1]); | ||
202 | return index-start; | 205 | return index-start; |
203 | } | 206 | } |
204 | 207 | ||
@@ -236,12 +239,17 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit, | |||
236 | s = rest_of_page(data); | 239 | s = rest_of_page(data); |
237 | if (s > count) | 240 | if (s > count) |
238 | s = count; | 241 | s = count; |
242 | /* Make sure we don't terminate early. */ | ||
243 | sg_unmark_end(&sg[index]); | ||
239 | sg_set_page(&sg[index++], pdata[i++], s, data_off); | 244 | sg_set_page(&sg[index++], pdata[i++], s, data_off); |
240 | data_off = 0; | 245 | data_off = 0; |
241 | data += s; | 246 | data += s; |
242 | count -= s; | 247 | count -= s; |
243 | nr_pages--; | 248 | nr_pages--; |
244 | } | 249 | } |
250 | |||
251 | if (index-start) | ||
252 | sg_mark_end(&sg[index - 1]); | ||
245 | return index - start; | 253 | return index - start; |
246 | } | 254 | } |
247 | 255 | ||
@@ -256,9 +264,10 @@ static int | |||
256 | p9_virtio_request(struct p9_client *client, struct p9_req_t *req) | 264 | p9_virtio_request(struct p9_client *client, struct p9_req_t *req) |
257 | { | 265 | { |
258 | int err; | 266 | int err; |
259 | int in, out; | 267 | int in, out, out_sgs, in_sgs; |
260 | unsigned long flags; | 268 | unsigned long flags; |
261 | struct virtio_chan *chan = client->trans; | 269 | struct virtio_chan *chan = client->trans; |
270 | struct scatterlist *sgs[2]; | ||
262 | 271 | ||
263 | p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n"); | 272 | p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n"); |
264 | 273 | ||
@@ -266,14 +275,19 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) | |||
266 | req_retry: | 275 | req_retry: |
267 | spin_lock_irqsave(&chan->lock, flags); | 276 | spin_lock_irqsave(&chan->lock, flags); |
268 | 277 | ||
278 | out_sgs = in_sgs = 0; | ||
269 | /* Handle out VirtIO ring buffers */ | 279 | /* Handle out VirtIO ring buffers */ |
270 | out = pack_sg_list(chan->sg, 0, | 280 | out = pack_sg_list(chan->sg, 0, |
271 | VIRTQUEUE_NUM, req->tc->sdata, req->tc->size); | 281 | VIRTQUEUE_NUM, req->tc->sdata, req->tc->size); |
282 | if (out) | ||
283 | sgs[out_sgs++] = chan->sg; | ||
272 | 284 | ||
273 | in = pack_sg_list(chan->sg, out, | 285 | in = pack_sg_list(chan->sg, out, |
274 | VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity); | 286 | VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity); |
287 | if (in) | ||
288 | sgs[out_sgs + in_sgs++] = chan->sg + out; | ||
275 | 289 | ||
276 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc, | 290 | err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req->tc, |
277 | GFP_ATOMIC); | 291 | GFP_ATOMIC); |
278 | if (err < 0) { | 292 | if (err < 0) { |
279 | if (err == -ENOSPC) { | 293 | if (err == -ENOSPC) { |
@@ -289,7 +303,7 @@ req_retry: | |||
289 | } else { | 303 | } else { |
290 | spin_unlock_irqrestore(&chan->lock, flags); | 304 | spin_unlock_irqrestore(&chan->lock, flags); |
291 | p9_debug(P9_DEBUG_TRANS, | 305 | p9_debug(P9_DEBUG_TRANS, |
292 | "virtio rpc add_buf returned failure\n"); | 306 | "virtio rpc add_sgs returned failure\n"); |
293 | return -EIO; | 307 | return -EIO; |
294 | } | 308 | } |
295 | } | 309 | } |
@@ -351,11 +365,12 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, | |||
351 | char *uidata, char *uodata, int inlen, | 365 | char *uidata, char *uodata, int inlen, |
352 | int outlen, int in_hdr_len, int kern_buf) | 366 | int outlen, int in_hdr_len, int kern_buf) |
353 | { | 367 | { |
354 | int in, out, err; | 368 | int in, out, err, out_sgs, in_sgs; |
355 | unsigned long flags; | 369 | unsigned long flags; |
356 | int in_nr_pages = 0, out_nr_pages = 0; | 370 | int in_nr_pages = 0, out_nr_pages = 0; |
357 | struct page **in_pages = NULL, **out_pages = NULL; | 371 | struct page **in_pages = NULL, **out_pages = NULL; |
358 | struct virtio_chan *chan = client->trans; | 372 | struct virtio_chan *chan = client->trans; |
373 | struct scatterlist *sgs[4]; | ||
359 | 374 | ||
360 | p9_debug(P9_DEBUG_TRANS, "virtio request\n"); | 375 | p9_debug(P9_DEBUG_TRANS, "virtio request\n"); |
361 | 376 | ||
@@ -396,13 +411,22 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, | |||
396 | req->status = REQ_STATUS_SENT; | 411 | req->status = REQ_STATUS_SENT; |
397 | req_retry_pinned: | 412 | req_retry_pinned: |
398 | spin_lock_irqsave(&chan->lock, flags); | 413 | spin_lock_irqsave(&chan->lock, flags); |
414 | |||
415 | out_sgs = in_sgs = 0; | ||
416 | |||
399 | /* out data */ | 417 | /* out data */ |
400 | out = pack_sg_list(chan->sg, 0, | 418 | out = pack_sg_list(chan->sg, 0, |
401 | VIRTQUEUE_NUM, req->tc->sdata, req->tc->size); | 419 | VIRTQUEUE_NUM, req->tc->sdata, req->tc->size); |
402 | 420 | ||
403 | if (out_pages) | 421 | if (out) |
422 | sgs[out_sgs++] = chan->sg; | ||
423 | |||
424 | if (out_pages) { | ||
425 | sgs[out_sgs++] = chan->sg + out; | ||
404 | out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, | 426 | out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, |
405 | out_pages, out_nr_pages, uodata, outlen); | 427 | out_pages, out_nr_pages, uodata, outlen); |
428 | } | ||
429 | |||
406 | /* | 430 | /* |
407 | * Take care of in data | 431 | * Take care of in data |
408 | * For example TREAD have 11. | 432 | * For example TREAD have 11. |
@@ -412,11 +436,17 @@ req_retry_pinned: | |||
412 | */ | 436 | */ |
413 | in = pack_sg_list(chan->sg, out, | 437 | in = pack_sg_list(chan->sg, out, |
414 | VIRTQUEUE_NUM, req->rc->sdata, in_hdr_len); | 438 | VIRTQUEUE_NUM, req->rc->sdata, in_hdr_len); |
415 | if (in_pages) | 439 | if (in) |
440 | sgs[out_sgs + in_sgs++] = chan->sg + out; | ||
441 | |||
442 | if (in_pages) { | ||
443 | sgs[out_sgs + in_sgs++] = chan->sg + out + in; | ||
416 | in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, | 444 | in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, |
417 | in_pages, in_nr_pages, uidata, inlen); | 445 | in_pages, in_nr_pages, uidata, inlen); |
446 | } | ||
418 | 447 | ||
419 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc, | 448 | BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs)); |
449 | err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req->tc, | ||
420 | GFP_ATOMIC); | 450 | GFP_ATOMIC); |
421 | if (err < 0) { | 451 | if (err < 0) { |
422 | if (err == -ENOSPC) { | 452 | if (err == -ENOSPC) { |
@@ -432,7 +462,7 @@ req_retry_pinned: | |||
432 | } else { | 462 | } else { |
433 | spin_unlock_irqrestore(&chan->lock, flags); | 463 | spin_unlock_irqrestore(&chan->lock, flags); |
434 | p9_debug(P9_DEBUG_TRANS, | 464 | p9_debug(P9_DEBUG_TRANS, |
435 | "virtio rpc add_buf returned failure\n"); | 465 | "virtio rpc add_sgs returned failure\n"); |
436 | err = -EIO; | 466 | err = -EIO; |
437 | goto err_out; | 467 | goto err_out; |
438 | } | 468 | } |