diff options
Diffstat (limited to 'net/9p')
-rw-r--r-- | net/9p/client.c | 3 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 46 |
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 | ||
223 | req_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 | ||
344 | out_free_tag: | ||
345 | kfree(tag); | ||
315 | out_free_vq: | 346 | out_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 | } |