diff options
| author | Venkateswararao Jujjuri (JV) <jvrao@linux.vnet.ibm.com> | 2010-09-29 21:33:41 -0400 |
|---|---|---|
| committer | Eric Van Hensbergen <ericvh@gmail.com> | 2010-10-28 10:08:48 -0400 |
| commit | 52f44e0d08ff1a065bf06615483c608163575cb1 (patch) | |
| tree | 44292212cecafac6ed870812b882b9af545bdaa6 | |
| parent | 419b39561e698d73a42f8010655d22e0134486da (diff) | |
net/9p: Add waitq to VirtIO transport.
If there is not enough space for the PDU on the VirtIO ring, current
code returns -EIO propagating the error to user.
This patch introduced a wqit_queue on the channel, and lets the process
wait on this queue until VirtIO ring frees up.
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
| -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 | } |
