aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p
diff options
context:
space:
mode:
Diffstat (limited to 'net/9p')
-rw-r--r--net/9p/client.c3
-rw-r--r--net/9p/trans_virtio.c46
2 files changed, 41 insertions, 8 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index 2bc99e9031e7..bc7b03537699 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -583,7 +583,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
583 583
584 err = c->trans_mod->request(c, req); 584 err = c->trans_mod->request(c, req);
585 if (err < 0) { 585 if (err < 0) {
586 c->status = Disconnected; 586 if (err != -ERESTARTSYS)
587 c->status = Disconnected;
587 goto reterr; 588 goto reterr;
588 } 589 }
589 590
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 8ae08596aad8..c8f3f72ab20e 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -75,6 +75,8 @@ struct virtio_chan {
75 struct p9_client *client; 75 struct p9_client *client;
76 struct virtio_device *vdev; 76 struct virtio_device *vdev;
77 struct virtqueue *vq; 77 struct virtqueue *vq;
78 int ring_bufs_avail;
79 wait_queue_head_t *vc_wq;
78 80
79 /* Scatterlist: can be too big for stack. */ 81 /* Scatterlist: can be too big for stack. */
80 struct scatterlist sg[VIRTQUEUE_NUM]; 82 struct scatterlist sg[VIRTQUEUE_NUM];
@@ -141,15 +143,21 @@ static void req_done(struct virtqueue *vq)
141 do { 143 do {
142 spin_lock_irqsave(&chan->lock, flags); 144 spin_lock_irqsave(&chan->lock, flags);
143 rc = virtqueue_get_buf(chan->vq, &len); 145 rc = virtqueue_get_buf(chan->vq, &len);
144 spin_unlock_irqrestore(&chan->lock, flags);
145 146
146 if (rc != NULL) { 147 if (rc != NULL) {
148 if (!chan->ring_bufs_avail) {
149 chan->ring_bufs_avail = 1;
150 wake_up(chan->vc_wq);
151 }
152 spin_unlock_irqrestore(&chan->lock, flags);
147 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); 153 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
148 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", 154 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n",
149 rc->tag); 155 rc->tag);
150 req = p9_tag_lookup(chan->client, rc->tag); 156 req = p9_tag_lookup(chan->client, rc->tag);
151 req->status = REQ_STATUS_RCVD; 157 req->status = REQ_STATUS_RCVD;
152 p9_client_cb(chan->client, req); 158 p9_client_cb(chan->client, req);
159 } else {
160 spin_unlock_irqrestore(&chan->lock, flags);
153 } 161 }
154 } while (rc != NULL); 162 } while (rc != NULL);
155} 163}
@@ -212,6 +220,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
212 220
213 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); 221 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
214 222
223req_retry:
215 req->status = REQ_STATUS_SENT; 224 req->status = REQ_STATUS_SENT;
216 225
217 spin_lock_irqsave(&chan->lock, flags); 226 spin_lock_irqsave(&chan->lock, flags);
@@ -222,10 +231,23 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
222 231
223 err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); 232 err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
224 if (err < 0) { 233 if (err < 0) {
225 spin_unlock_irqrestore(&chan->lock, flags); 234 if (err == -ENOSPC) {
226 P9_DPRINTK(P9_DEBUG_TRANS, 235 chan->ring_bufs_avail = 0;
227 "9p debug: virtio rpc add_buf returned failure"); 236 spin_unlock_irqrestore(&chan->lock, flags);
228 return -EIO; 237 err = wait_event_interruptible(*chan->vc_wq,
238 chan->ring_bufs_avail);
239 if (err == -ERESTARTSYS)
240 return err;
241
242 P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
243 goto req_retry;
244 } else {
245 spin_unlock_irqrestore(&chan->lock, flags);
246 P9_DPRINTK(P9_DEBUG_TRANS,
247 "9p debug: "
248 "virtio rpc add_buf returned failure");
249 return -EIO;
250 }
229 } 251 }
230 252
231 virtqueue_kick(chan->vq); 253 virtqueue_kick(chan->vq);
@@ -304,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev)
304 chan->tag_len = tag_len; 326 chan->tag_len = tag_len;
305 err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); 327 err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
306 if (err) { 328 if (err) {
307 kfree(tag); 329 goto out_free_tag;
308 goto out_free_vq;
309 } 330 }
331 chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
332 if (!chan->vc_wq) {
333 err = -ENOMEM;
334 goto out_free_tag;
335 }
336 init_waitqueue_head(chan->vc_wq);
337 chan->ring_bufs_avail = 1;
338
310 mutex_lock(&virtio_9p_lock); 339 mutex_lock(&virtio_9p_lock);
311 list_add_tail(&chan->chan_list, &virtio_chan_list); 340 list_add_tail(&chan->chan_list, &virtio_chan_list);
312 mutex_unlock(&virtio_9p_lock); 341 mutex_unlock(&virtio_9p_lock);
313 return 0; 342 return 0;
314 343
344out_free_tag:
345 kfree(tag);
315out_free_vq: 346out_free_vq:
316 vdev->config->del_vqs(vdev); 347 vdev->config->del_vqs(vdev);
317 kfree(chan); 348 kfree(chan);
@@ -385,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
385 mutex_unlock(&virtio_9p_lock); 416 mutex_unlock(&virtio_9p_lock);
386 sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); 417 sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
387 kfree(chan->tag); 418 kfree(chan->tag);
419 kfree(chan->vc_wq);
388 kfree(chan); 420 kfree(chan);
389 421
390} 422}