diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 16:25:11 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 16:25:11 (GMT) |
commit | 90a2b69c14d0f0b6cbd124caf429ae9033f0615c (patch) | |
tree | 9aa18ac045eec9515ed225f900717e8a5f4fd8d6 /net/9p/trans_virtio.c | |
parent | e430426654c6a99fb1977bae71d4844e876c4a52 (diff) | |
parent | f6ac55b6c156cebf750376dc08e06ffdade82717 (diff) | |
download | linux-fsl-qoriq-90a2b69c14d0f0b6cbd124caf429ae9033f0615c.tar.xz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: (28 commits)
net/9p: Return error on read with NULL buffer
9p: Add datasync to client side TFSYNC/RFSYNC for dotl
net/9p: Return error if we fail to encode protocol data
fs/9p: Use generic_file_open with lookup_instantiate_filp
fs/9p: Add missing iput in v9fs_vfs_lookup
fs/9p: Use mknod 9p operation on create without open request
net/9p: Add waitq to VirtIO transport.
[net/9p]Serialize virtqueue operations to make VirtIO transport SMP safe.
9p: Implement TREADLINK operation for 9p2000.L
9p: Use V9FS_MAGIC in statfs
9p: Implement TGETLOCK
9p: Implement TLOCK
[9p] Introduce client side TFSYNC/RFSYNC for dotl.
[fs/9p] Add file_operations for cached mode in dotl protocol.
fs/9p: Add access = client option to opt in acl evaluation.
fs/9p: Implement create time inheritance
fs/9p: Update ACL on chmod
fs/9p: Implement setting posix acl
fs/9p: Add xattr callbacks for POSIX ACL
fs/9p: Implement POSIX ACL permission checking function
...
Diffstat (limited to 'net/9p/trans_virtio.c')
-rw-r--r-- | net/9p/trans_virtio.c | 76 |
1 files changed, 61 insertions, 15 deletions
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index b885159..c8f3f72 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -75,6 +75,8 @@ struct virtio_chan { struct p9_client *client; struct virtio_device *vdev; struct virtqueue *vq; + int ring_bufs_avail; + wait_queue_head_t *vc_wq; /* Scatterlist: can be too big for stack. */ struct scatterlist sg[VIRTQUEUE_NUM]; @@ -134,16 +136,30 @@ static void req_done(struct virtqueue *vq) struct p9_fcall *rc; unsigned int len; struct p9_req_t *req; + unsigned long flags; P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); - while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) { - P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); - P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); - req = p9_tag_lookup(chan->client, rc->tag); - req->status = REQ_STATUS_RCVD; - p9_client_cb(chan->client, req); - } + do { + spin_lock_irqsave(&chan->lock, flags); + rc = virtqueue_get_buf(chan->vq, &len); + + if (rc != NULL) { + if (!chan->ring_bufs_avail) { + chan->ring_bufs_avail = 1; + wake_up(chan->vc_wq); + } + spin_unlock_irqrestore(&chan->lock, flags); + P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); + P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", + rc->tag); + req = p9_tag_lookup(chan->client, rc->tag); + req->status = REQ_STATUS_RCVD; + p9_client_cb(chan->client, req); + } else { + spin_unlock_irqrestore(&chan->lock, flags); + } + } while (rc != NULL); } /** @@ -199,23 +215,43 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) int in, out; struct virtio_chan *chan = client->trans; char *rdata = (char *)req->rc+sizeof(struct p9_fcall); + unsigned long flags; + int err; P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); +req_retry: + req->status = REQ_STATUS_SENT; + + spin_lock_irqsave(&chan->lock, flags); out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, req->tc->size); in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, client->msize); - req->status = REQ_STATUS_SENT; - - if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) { - P9_DPRINTK(P9_DEBUG_TRANS, - "9p debug: virtio rpc add_buf returned failure"); - return -EIO; + err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); + if (err < 0) { + if (err == -ENOSPC) { + chan->ring_bufs_avail = 0; + spin_unlock_irqrestore(&chan->lock, flags); + err = wait_event_interruptible(*chan->vc_wq, + chan->ring_bufs_avail); + if (err == -ERESTARTSYS) + return err; + + P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); + goto req_retry; + } else { + spin_unlock_irqrestore(&chan->lock, flags); + P9_DPRINTK(P9_DEBUG_TRANS, + "9p debug: " + "virtio rpc add_buf returned failure"); + return -EIO; + } } virtqueue_kick(chan->vq); + spin_unlock_irqrestore(&chan->lock, flags); P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); return 0; @@ -290,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev) chan->tag_len = tag_len; err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); if (err) { - kfree(tag); - goto out_free_vq; + goto out_free_tag; } + chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); + if (!chan->vc_wq) { + err = -ENOMEM; + goto out_free_tag; + } + init_waitqueue_head(chan->vc_wq); + chan->ring_bufs_avail = 1; + mutex_lock(&virtio_9p_lock); list_add_tail(&chan->chan_list, &virtio_chan_list); mutex_unlock(&virtio_9p_lock); return 0; +out_free_tag: + kfree(tag); out_free_vq: vdev->config->del_vqs(vdev); kfree(chan); @@ -371,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev) mutex_unlock(&virtio_9p_lock); sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); kfree(chan->tag); + kfree(chan->vc_wq); kfree(chan); } |