|
@@ -49,8 +49,6 @@
|
|
|
|
|
|
/* a single mutex to manage channel initialization and attachment */
|
|
|
static DEFINE_MUTEX(virtio_9p_lock);
|
|
|
-/* global which tracks highest initialized channel */
|
|
|
-static int chan_index;
|
|
|
|
|
|
/**
|
|
|
* struct virtio_chan - per-instance transport information
|
|
@@ -68,8 +66,7 @@ static int chan_index;
|
|
|
*
|
|
|
*/
|
|
|
|
|
|
-static struct virtio_chan {
|
|
|
- bool initialized;
|
|
|
+struct virtio_chan {
|
|
|
bool inuse;
|
|
|
|
|
|
spinlock_t lock;
|
|
@@ -80,7 +77,11 @@ static struct virtio_chan {
|
|
|
|
|
|
/* Scatterlist: can be too big for stack. */
|
|
|
struct scatterlist sg[VIRTQUEUE_NUM];
|
|
|
-} channels[MAX_9P_CHAN];
|
|
|
+
|
|
|
+ struct list_head chan_list;
|
|
|
+};
|
|
|
+
|
|
|
+static struct list_head virtio_chan_list;
|
|
|
|
|
|
/* How many bytes left in this page. */
|
|
|
static unsigned int rest_of_page(void *data)
|
|
@@ -217,9 +218,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
|
|
|
* p9_virtio_probe - probe for existence of 9P virtio channels
|
|
|
* @vdev: virtio device to probe
|
|
|
*
|
|
|
- * This probes for existing virtio channels. At present only
|
|
|
- * a single channel is in use, so in the future more work may need
|
|
|
- * to be done here.
|
|
|
+ * This probes for existing virtio channels.
|
|
|
*
|
|
|
*/
|
|
|
|
|
@@ -227,16 +226,10 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
|
|
{
|
|
|
int err;
|
|
|
struct virtio_chan *chan;
|
|
|
- int index;
|
|
|
|
|
|
- mutex_lock(&virtio_9p_lock);
|
|
|
- index = chan_index++;
|
|
|
- chan = &channels[index];
|
|
|
- mutex_unlock(&virtio_9p_lock);
|
|
|
-
|
|
|
- if (chan_index > MAX_9P_CHAN) {
|
|
|
- printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
|
|
|
- BUG();
|
|
|
+ chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
|
|
|
+ if (!chan) {
|
|
|
+ printk(KERN_ERR "9p: Failed to allocate virtio 9P channel\n");
|
|
|
err = -ENOMEM;
|
|
|
goto fail;
|
|
|
}
|
|
@@ -255,15 +248,15 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
|
|
sg_init_table(chan->sg, VIRTQUEUE_NUM);
|
|
|
|
|
|
chan->inuse = false;
|
|
|
- chan->initialized = true;
|
|
|
+ mutex_lock(&virtio_9p_lock);
|
|
|
+ list_add_tail(&chan->chan_list, &virtio_chan_list);
|
|
|
+ mutex_unlock(&virtio_9p_lock);
|
|
|
return 0;
|
|
|
|
|
|
out_free_vq:
|
|
|
vdev->config->del_vqs(vdev);
|
|
|
+ kfree(chan);
|
|
|
fail:
|
|
|
- mutex_lock(&virtio_9p_lock);
|
|
|
- chan_index--;
|
|
|
- mutex_unlock(&virtio_9p_lock);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -280,35 +273,27 @@ fail:
|
|
|
* We use a simple reference count mechanism to ensure that only a single
|
|
|
* mount has a channel open at a time.
|
|
|
*
|
|
|
- * Bugs: doesn't allow identification of a specific channel
|
|
|
- * to allocate, channels are allocated sequentially. This was
|
|
|
- * a pragmatic decision to get things rolling, but ideally some
|
|
|
- * way of identifying the channel to attach to would be nice
|
|
|
- * if we are going to support multiple channels.
|
|
|
- *
|
|
|
*/
|
|
|
|
|
|
static int
|
|
|
p9_virtio_create(struct p9_client *client, const char *devname, char *args)
|
|
|
{
|
|
|
- struct virtio_chan *chan = channels;
|
|
|
- int index = 0;
|
|
|
+ struct virtio_chan *chan;
|
|
|
+ int found = 0;
|
|
|
|
|
|
mutex_lock(&virtio_9p_lock);
|
|
|
- while (index < MAX_9P_CHAN) {
|
|
|
- if (chan->initialized &&
|
|
|
- !strcmp(devname, dev_name(&chan->vdev->dev))) {
|
|
|
+ list_for_each_entry(chan, &virtio_chan_list, chan_list) {
|
|
|
+ if (!strcmp(devname, dev_name(&chan->vdev->dev))) {
|
|
|
if (!chan->inuse) {
|
|
|
chan->inuse = true;
|
|
|
+ found = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- index++;
|
|
|
- chan = &channels[index];
|
|
|
}
|
|
|
mutex_unlock(&virtio_9p_lock);
|
|
|
|
|
|
- if (index >= MAX_9P_CHAN) {
|
|
|
+ if (!found) {
|
|
|
printk(KERN_ERR "9p: no channels available\n");
|
|
|
return -ENODEV;
|
|
|
}
|
|
@@ -331,11 +316,13 @@ static void p9_virtio_remove(struct virtio_device *vdev)
|
|
|
struct virtio_chan *chan = vdev->priv;
|
|
|
|
|
|
BUG_ON(chan->inuse);
|
|
|
+ vdev->config->del_vqs(vdev);
|
|
|
+
|
|
|
+ mutex_lock(&virtio_9p_lock);
|
|
|
+ list_del(&chan->chan_list);
|
|
|
+ mutex_unlock(&virtio_9p_lock);
|
|
|
+ kfree(chan);
|
|
|
|
|
|
- if (chan->initialized) {
|
|
|
- vdev->config->del_vqs(vdev);
|
|
|
- chan->initialized = false;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
static struct virtio_device_id id_table[] = {
|
|
@@ -366,10 +353,7 @@ static struct p9_trans_module p9_virtio_trans = {
|
|
|
/* The standard init function */
|
|
|
static int __init p9_virtio_init(void)
|
|
|
{
|
|
|
- int count;
|
|
|
-
|
|
|
- for (count = 0; count < MAX_9P_CHAN; count++)
|
|
|
- channels[count].initialized = false;
|
|
|
+ INIT_LIST_HEAD(&virtio_chan_list);
|
|
|
|
|
|
v9fs_register_trans(&p9_virtio_trans);
|
|
|
return register_virtio_driver(&p9_virtio_drv);
|