aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p/trans_virtio.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/9p/trans_virtio.c')
-rw-r--r--net/9p/trans_virtio.c147
1 files changed, 95 insertions, 52 deletions
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index ea1e3daabefe..7eb78ecc1618 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -37,6 +37,7 @@
37#include <linux/inet.h> 37#include <linux/inet.h>
38#include <linux/idr.h> 38#include <linux/idr.h>
39#include <linux/file.h> 39#include <linux/file.h>
40#include <linux/slab.h>
40#include <net/9p/9p.h> 41#include <net/9p/9p.h>
41#include <linux/parser.h> 42#include <linux/parser.h>
42#include <net/9p/client.h> 43#include <net/9p/client.h>
@@ -49,8 +50,6 @@
49 50
50/* a single mutex to manage channel initialization and attachment */ 51/* a single mutex to manage channel initialization and attachment */
51static DEFINE_MUTEX(virtio_9p_lock); 52static DEFINE_MUTEX(virtio_9p_lock);
52/* global which tracks highest initialized channel */
53static int chan_index;
54 53
55/** 54/**
56 * struct virtio_chan - per-instance transport information 55 * struct virtio_chan - per-instance transport information
@@ -68,8 +67,7 @@ static int chan_index;
68 * 67 *
69 */ 68 */
70 69
71static struct virtio_chan { 70struct virtio_chan {
72 bool initialized;
73 bool inuse; 71 bool inuse;
74 72
75 spinlock_t lock; 73 spinlock_t lock;
@@ -80,7 +78,17 @@ static struct virtio_chan {
80 78
81 /* Scatterlist: can be too big for stack. */ 79 /* Scatterlist: can be too big for stack. */
82 struct scatterlist sg[VIRTQUEUE_NUM]; 80 struct scatterlist sg[VIRTQUEUE_NUM];
83} channels[MAX_9P_CHAN]; 81
82 int tag_len;
83 /*
84 * tag name to identify a mount Non-null terminated
85 */
86 char *tag;
87
88 struct list_head chan_list;
89};
90
91static struct list_head virtio_chan_list;
84 92
85/* How many bytes left in this page. */ 93/* How many bytes left in this page. */
86static unsigned int rest_of_page(void *data) 94static unsigned int rest_of_page(void *data)
@@ -102,7 +110,8 @@ static void p9_virtio_close(struct p9_client *client)
102 struct virtio_chan *chan = client->trans; 110 struct virtio_chan *chan = client->trans;
103 111
104 mutex_lock(&virtio_9p_lock); 112 mutex_lock(&virtio_9p_lock);
105 chan->inuse = false; 113 if (chan)
114 chan->inuse = false;
106 mutex_unlock(&virtio_9p_lock); 115 mutex_unlock(&virtio_9p_lock);
107} 116}
108 117
@@ -212,30 +221,38 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
212 return 0; 221 return 0;
213} 222}
214 223
224static ssize_t p9_mount_tag_show(struct device *dev,
225 struct device_attribute *attr, char *buf)
226{
227 struct virtio_chan *chan;
228 struct virtio_device *vdev;
229
230 vdev = dev_to_virtio(dev);
231 chan = vdev->priv;
232
233 return snprintf(buf, chan->tag_len + 1, "%s", chan->tag);
234}
235
236static DEVICE_ATTR(mount_tag, 0444, p9_mount_tag_show, NULL);
237
215/** 238/**
216 * p9_virtio_probe - probe for existence of 9P virtio channels 239 * p9_virtio_probe - probe for existence of 9P virtio channels
217 * @vdev: virtio device to probe 240 * @vdev: virtio device to probe
218 * 241 *
219 * This probes for existing virtio channels. At present only 242 * This probes for existing virtio channels.
220 * a single channel is in use, so in the future more work may need
221 * to be done here.
222 * 243 *
223 */ 244 */
224 245
225static int p9_virtio_probe(struct virtio_device *vdev) 246static int p9_virtio_probe(struct virtio_device *vdev)
226{ 247{
248 __u16 tag_len;
249 char *tag;
227 int err; 250 int err;
228 struct virtio_chan *chan; 251 struct virtio_chan *chan;
229 int index;
230 252
231 mutex_lock(&virtio_9p_lock); 253 chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
232 index = chan_index++; 254 if (!chan) {
233 chan = &channels[index]; 255 printk(KERN_ERR "9p: Failed to allocate virtio 9P channel\n");
234 mutex_unlock(&virtio_9p_lock);
235
236 if (chan_index > MAX_9P_CHAN) {
237 printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
238 BUG();
239 err = -ENOMEM; 256 err = -ENOMEM;
240 goto fail; 257 goto fail;
241 } 258 }
@@ -254,15 +271,37 @@ static int p9_virtio_probe(struct virtio_device *vdev)
254 sg_init_table(chan->sg, VIRTQUEUE_NUM); 271 sg_init_table(chan->sg, VIRTQUEUE_NUM);
255 272
256 chan->inuse = false; 273 chan->inuse = false;
257 chan->initialized = true; 274 if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) {
275 vdev->config->get(vdev,
276 offsetof(struct virtio_9p_config, tag_len),
277 &tag_len, sizeof(tag_len));
278 } else {
279 err = -EINVAL;
280 goto out_free_vq;
281 }
282 tag = kmalloc(tag_len, GFP_KERNEL);
283 if (!tag) {
284 err = -ENOMEM;
285 goto out_free_vq;
286 }
287 vdev->config->get(vdev, offsetof(struct virtio_9p_config, tag),
288 tag, tag_len);
289 chan->tag = tag;
290 chan->tag_len = tag_len;
291 err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
292 if (err) {
293 kfree(tag);
294 goto out_free_vq;
295 }
296 mutex_lock(&virtio_9p_lock);
297 list_add_tail(&chan->chan_list, &virtio_chan_list);
298 mutex_unlock(&virtio_9p_lock);
258 return 0; 299 return 0;
259 300
260out_free_vq: 301out_free_vq:
261 vdev->config->del_vqs(vdev); 302 vdev->config->del_vqs(vdev);
303 kfree(chan);
262fail: 304fail:
263 mutex_lock(&virtio_9p_lock);
264 chan_index--;
265 mutex_unlock(&virtio_9p_lock);
266 return err; 305 return err;
267} 306}
268 307
@@ -279,38 +318,35 @@ fail:
279 * We use a simple reference count mechanism to ensure that only a single 318 * We use a simple reference count mechanism to ensure that only a single
280 * mount has a channel open at a time. 319 * mount has a channel open at a time.
281 * 320 *
282 * Bugs: doesn't allow identification of a specific channel
283 * to allocate, channels are allocated sequentially. This was
284 * a pragmatic decision to get things rolling, but ideally some
285 * way of identifying the channel to attach to would be nice
286 * if we are going to support multiple channels.
287 *
288 */ 321 */
289 322
290static int 323static int
291p9_virtio_create(struct p9_client *client, const char *devname, char *args) 324p9_virtio_create(struct p9_client *client, const char *devname, char *args)
292{ 325{
293 struct virtio_chan *chan = channels; 326 struct virtio_chan *chan;
294 int index = 0; 327 int ret = -ENOENT;
328 int found = 0;
295 329
296 mutex_lock(&virtio_9p_lock); 330 mutex_lock(&virtio_9p_lock);
297 while (index < MAX_9P_CHAN) { 331 list_for_each_entry(chan, &virtio_chan_list, chan_list) {
298 if (chan->initialized && !chan->inuse) { 332 if (!strncmp(devname, chan->tag, chan->tag_len)) {
299 chan->inuse = true; 333 if (!chan->inuse) {
300 break; 334 chan->inuse = true;
301 } else { 335 found = 1;
302 index++; 336 break;
303 chan = &channels[index]; 337 }
338 ret = -EBUSY;
304 } 339 }
305 } 340 }
306 mutex_unlock(&virtio_9p_lock); 341 mutex_unlock(&virtio_9p_lock);
307 342
308 if (index >= MAX_9P_CHAN) { 343 if (!found) {
309 printk(KERN_ERR "9p: no channels available\n"); 344 printk(KERN_ERR "9p: no channels available\n");
310 return -ENODEV; 345 return ret;
311 } 346 }
312 347
313 client->trans = (void *)chan; 348 client->trans = (void *)chan;
349 client->status = Connected;
314 chan->client = client; 350 chan->client = client;
315 351
316 return 0; 352 return 0;
@@ -327,11 +363,15 @@ static void p9_virtio_remove(struct virtio_device *vdev)
327 struct virtio_chan *chan = vdev->priv; 363 struct virtio_chan *chan = vdev->priv;
328 364
329 BUG_ON(chan->inuse); 365 BUG_ON(chan->inuse);
366 vdev->config->del_vqs(vdev);
367
368 mutex_lock(&virtio_9p_lock);
369 list_del(&chan->chan_list);
370 mutex_unlock(&virtio_9p_lock);
371 sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
372 kfree(chan->tag);
373 kfree(chan);
330 374
331 if (chan->initialized) {
332 vdev->config->del_vqs(vdev);
333 chan->initialized = false;
334 }
335} 375}
336 376
337static struct virtio_device_id id_table[] = { 377static struct virtio_device_id id_table[] = {
@@ -339,13 +379,19 @@ static struct virtio_device_id id_table[] = {
339 { 0 }, 379 { 0 },
340}; 380};
341 381
382static unsigned int features[] = {
383 VIRTIO_9P_MOUNT_TAG,
384};
385
342/* The standard "struct lguest_driver": */ 386/* The standard "struct lguest_driver": */
343static struct virtio_driver p9_virtio_drv = { 387static struct virtio_driver p9_virtio_drv = {
344 .driver.name = KBUILD_MODNAME, 388 .feature_table = features,
345 .driver.owner = THIS_MODULE, 389 .feature_table_size = ARRAY_SIZE(features),
346 .id_table = id_table, 390 .driver.name = KBUILD_MODNAME,
347 .probe = p9_virtio_probe, 391 .driver.owner = THIS_MODULE,
348 .remove = p9_virtio_remove, 392 .id_table = id_table,
393 .probe = p9_virtio_probe,
394 .remove = p9_virtio_remove,
349}; 395};
350 396
351static struct p9_trans_module p9_virtio_trans = { 397static struct p9_trans_module p9_virtio_trans = {
@@ -362,10 +408,7 @@ static struct p9_trans_module p9_virtio_trans = {
362/* The standard init function */ 408/* The standard init function */
363static int __init p9_virtio_init(void) 409static int __init p9_virtio_init(void)
364{ 410{
365 int count; 411 INIT_LIST_HEAD(&virtio_chan_list);
366
367 for (count = 0; count < MAX_9P_CHAN; count++)
368 channels[count].initialized = false;
369 412
370 v9fs_register_trans(&p9_virtio_trans); 413 v9fs_register_trans(&p9_virtio_trans);
371 return register_virtio_driver(&p9_virtio_drv); 414 return register_virtio_driver(&p9_virtio_drv);