···4243 trans=name select an alternative transport. Valid options are44 currently:45- unix - specifying a named pipe mount point46- tcp - specifying a normal TCP/IP connection47- fd - used passed file descriptors for connection48 (see rfdno and wfdno)004950 uname=name user name to attempt mount as on the remote server. The51 server may override or ignore this value. Certain user
···4243 trans=name select an alternative transport. Valid options are44 currently:45+ unix - specifying a named pipe mount point46+ tcp - specifying a normal TCP/IP connection47+ fd - used passed file descriptors for connection48 (see rfdno and wfdno)49+ virtio - connect to the next virtio channel available50+ (from lguest or KVM with trans_virtio module)5152 uname=name user name to attempt mount as on the remote server. The53 server may override or ignore this value. Certain user
+10
include/linux/virtio_9p.h
···0000000000
···1+#ifndef _LINUX_VIRTIO_9P_H2+#define _LINUX_VIRTIO_9P_H3+#include <linux/virtio_config.h>4+5+/* The ID for virtio console */6+#define VIRTIO_ID_9P 97+/* Maximum number of virtio channels per partition (1 for now) */8+#define MAX_9P_CHAN 19+10+#endif /* _LINUX_VIRTIO_9P_H */
+7
net/9p/Kconfig
···23 file descriptors. TCP/IP is the default transport for 9p,24 so if you are going to use 9p, you'll likely want this.25000000026config NET_9P_DEBUG27 bool "Debug information"28 depends on NET_9P
···23 file descriptors. TCP/IP is the default transport for 9p,24 so if you are going to use 9p, you'll likely want this.2526+config NET_9P_VIRTIO27+ depends on NET_9P && EXPERIMENTAL && VIRTIO28+ tristate "9P Virtio Transport (Experimental)"29+ help30+ This builds support for a transports between31+ guest partitions and a host partition.32+33config NET_9P_DEBUG34 bool "Debug information"35 depends on NET_9P
···1+/*2+ * The Guest 9p transport driver3+ *4+ * This is a trivial pipe-based transport driver based on the lguest console5+ * code: we use lguest's DMA mechanism to send bytes out, and register a6+ * DMA buffer to receive bytes in. It is assumed to be present and available7+ * from the very beginning of boot.8+ *9+ * This may be have been done by just instaniating another HVC console,10+ * but HVC's blocksize of 16 bytes is annoying and painful to performance.11+ *12+ * A more efficient transport could be built based on the virtio block driver13+ * but it requires some changes in the 9p transport model (which are in14+ * progress)15+ *16+ */17+/*18+ * Copyright (C) 2007 Eric Van Hensbergen, IBM Corporation19+ *20+ * Based on virtio console driver21+ * Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation22+ *23+ * This program is free software; you can redistribute it and/or modify24+ * it under the terms of the GNU General Public License version 225+ * as published by the Free Software Foundation.26+ *27+ * This program is distributed in the hope that it will be useful,28+ * but WITHOUT ANY WARRANTY; without even the implied warranty of29+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the30+ * GNU General Public License for more details.31+ *32+ * You should have received a copy of the GNU General Public License33+ * along with this program; if not, write to:34+ * Free Software Foundation35+ * 51 Franklin Street, Fifth Floor36+ * Boston, MA 02111-1301 USA37+ *38+ */39+40+#include <linux/in.h>41+#include <linux/module.h>42+#include <linux/net.h>43+#include <linux/ipv6.h>44+#include <linux/errno.h>45+#include <linux/kernel.h>46+#include <linux/un.h>47+#include <linux/uaccess.h>48+#include <linux/inet.h>49+#include <linux/idr.h>50+#include <linux/file.h>51+#include <net/9p/9p.h>52+#include <linux/parser.h>53+#include <net/9p/transport.h>54+#include <linux/scatterlist.h>55+#include <linux/virtio.h>56+#include <linux/virtio_9p.h>57+58+/* a single mutex to manage channel initialization and attachment */59+static DECLARE_MUTEX(virtio_9p_lock);60+/* global which tracks highest initialized channel */61+static int chan_index;62+63+/* We keep all per-channel information in a structure.64+ * This structure is allocated within the devices dev->mem space.65+ * A pointer to the structure will get put in the transport private.66+ */67+static struct virtio_chan {68+ bool initialized; /* channel is initialized */69+ bool inuse; /* channel is in use */70+71+ struct virtqueue *in_vq, *out_vq;72+ struct virtio_device *vdev;73+74+ /* This is our input buffer, and how much data is left in it. */75+ unsigned int in_len;76+ char *in, *inbuf;77+78+ wait_queue_head_t wq; /* waitq for buffer */79+} channels[MAX_9P_CHAN];80+81+/* How many bytes left in this page. */82+static unsigned int rest_of_page(void *data)83+{84+ return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);85+}86+87+static int p9_virtio_write(struct p9_trans *trans, void *buf, int count)88+{89+ struct virtio_chan *chan = (struct virtio_chan *) trans->priv;90+ struct virtqueue *out_vq = chan->out_vq;91+ struct scatterlist sg[1];92+ unsigned int len;93+94+ P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio write (%d)\n", count);95+96+ /* keep it simple - make sure we don't overflow a page */97+ if (rest_of_page(buf) < count)98+ count = rest_of_page(buf);99+100+ sg_init_one(sg, buf, count);101+102+ /* add_buf wants a token to identify this buffer: we hand it any103+ * non-NULL pointer, since there's only ever one buffer. */104+ if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {105+ /* Tell Host to go! */106+ out_vq->vq_ops->kick(out_vq);107+ /* Chill out until it's done with the buffer. */108+ while (!out_vq->vq_ops->get_buf(out_vq, &len))109+ cpu_relax();110+ }111+112+ P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio wrote (%d)\n", count);113+114+ /* We're expected to return the amount of data we wrote: all of it. */115+ return count;116+}117+118+/* Create a scatter-gather list representing our input buffer and put it in the119+ * queue. */120+static void add_inbuf(struct virtio_chan *chan)121+{122+ struct scatterlist sg[1];123+124+ sg_init_one(sg, chan->inbuf, PAGE_SIZE);125+126+ /* We should always be able to add one buffer to an empty queue. */127+ if (chan->in_vq->vq_ops->add_buf(chan->in_vq, sg, 0, 1, chan->inbuf))128+ BUG();129+ chan->in_vq->vq_ops->kick(chan->in_vq);130+}131+132+static int p9_virtio_read(struct p9_trans *trans, void *buf, int count)133+{134+ struct virtio_chan *chan = (struct virtio_chan *) trans->priv;135+ struct virtqueue *in_vq = chan->in_vq;136+137+ P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio read (%d)\n", count);138+139+ /* If we don't have an input queue yet, we can't get input. */140+ BUG_ON(!in_vq);141+142+ /* No buffer? Try to get one. */143+ if (!chan->in_len) {144+ chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);145+ if (!chan->in)146+ return 0;147+ }148+149+ /* You want more than we have to give? Well, try wanting less! */150+ if (chan->in_len < count)151+ count = chan->in_len;152+153+ /* Copy across to their buffer and increment offset. */154+ memcpy(buf, chan->in, count);155+ chan->in += count;156+ chan->in_len -= count;157+158+ /* Finished? Re-register buffer so Host will use it again. */159+ if (chan->in_len == 0)160+ add_inbuf(chan);161+162+ P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio finished read (%d)\n",163+ count);164+165+ return count;166+}167+168+/* The poll function is used by 9p transports to determine if there169+ * is there is activity available on a particular channel. In our case170+ * we use it to wait for a callback from the input routines.171+ */172+static unsigned int173+p9_virtio_poll(struct p9_trans *trans, struct poll_table_struct *pt)174+{175+ struct virtio_chan *chan = (struct virtio_chan *)trans->priv;176+ struct virtqueue *in_vq = chan->in_vq;177+ int ret = POLLOUT; /* we can always handle more output */178+179+ poll_wait(NULL, &chan->wq, pt);180+181+ /* No buffer? Try to get one. */182+ if (!chan->in_len)183+ chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);184+185+ if (chan->in_len)186+ ret |= POLLIN;187+188+ return ret;189+}190+191+static void p9_virtio_close(struct p9_trans *trans)192+{193+ struct virtio_chan *chan = trans->priv;194+195+ down(&virtio_9p_lock);196+ chan->inuse = false;197+ up(&virtio_9p_lock);198+199+ kfree(trans);200+}201+202+static bool p9_virtio_intr(struct virtqueue *q)203+{204+ struct virtio_chan *chan = q->vdev->priv;205+206+ P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq);207+ wake_up_interruptible(&chan->wq);208+209+ return true;210+}211+212+static int p9_virtio_probe(struct virtio_device *dev)213+{214+ int err;215+ struct virtio_chan *chan;216+ int index;217+218+ down(&virtio_9p_lock);219+ index = chan_index++;220+ chan = &channels[index];221+ up(&virtio_9p_lock);222+223+ if (chan_index > MAX_9P_CHAN) {224+ printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");225+ BUG();226+ }227+228+ chan->vdev = dev;229+230+ /* This is the scratch page we use to receive console input */231+ chan->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);232+ if (!chan->inbuf) {233+ err = -ENOMEM;234+ goto fail;235+ }236+237+ /* Find the input queue. */238+ dev->priv = chan;239+ chan->in_vq = dev->config->find_vq(dev, p9_virtio_intr);240+ if (IS_ERR(chan->in_vq)) {241+ err = PTR_ERR(chan->in_vq);242+ goto free;243+ }244+245+ chan->out_vq = dev->config->find_vq(dev, NULL);246+ if (IS_ERR(chan->out_vq)) {247+ err = PTR_ERR(chan->out_vq);248+ goto free_in_vq;249+ }250+251+ init_waitqueue_head(&chan->wq);252+253+ /* Register the input buffer the first time. */254+ add_inbuf(chan);255+ chan->inuse = false;256+ chan->initialized = true;257+258+ return 0;259+260+free_in_vq:261+ dev->config->del_vq(chan->in_vq);262+free:263+ kfree(chan->inbuf);264+fail:265+ down(&virtio_9p_lock);266+ chan_index--;267+ up(&virtio_9p_lock);268+ return err;269+}270+271+/* This sets up a transport channel for 9p communication. Right now272+ * we only match the first available channel, but eventually we couldlook up273+ * alternate channels by matching devname versus a virtio_config entry.274+ * We use a simple reference count mechanism to ensure that only a single275+ * mount has a channel open at a time. */276+static struct p9_trans *p9_virtio_create(const char *devname, char *args)277+{278+ struct p9_trans *trans;279+ int index = 0;280+ struct virtio_chan *chan = channels;281+282+ down(&virtio_9p_lock);283+ while (index < MAX_9P_CHAN) {284+ if (chan->initialized && !chan->inuse) {285+ chan->inuse = true;286+ break;287+ } else {288+ index++;289+ chan = &channels[index];290+ }291+ }292+ up(&virtio_9p_lock);293+294+ if (index >= MAX_9P_CHAN) {295+ printk(KERN_ERR "9p: virtio: couldn't find a free channel\n");296+ return NULL;297+ }298+299+ trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);300+ if (!trans) {301+ printk(KERN_ERR "9p: couldn't allocate transport\n");302+ return ERR_PTR(-ENOMEM);303+ }304+305+ trans->write = p9_virtio_write;306+ trans->read = p9_virtio_read;307+ trans->close = p9_virtio_close;308+ trans->poll = p9_virtio_poll;309+ trans->priv = chan;310+311+ return trans;312+}313+314+#define VIRTIO_ID_9P 9315+316+static struct virtio_device_id id_table[] = {317+ { VIRTIO_ID_9P, VIRTIO_DEV_ANY_ID },318+ { 0 },319+};320+321+/* The standard "struct lguest_driver": */322+static struct virtio_driver p9_virtio_drv = {323+ .driver.name = KBUILD_MODNAME,324+ .driver.owner = THIS_MODULE,325+ .id_table = id_table,326+ .probe = p9_virtio_probe,327+};328+329+static struct p9_trans_module p9_virtio_trans = {330+ .name = "virtio",331+ .create = p9_virtio_create,332+ .maxsize = PAGE_SIZE,333+ .def = 0,334+};335+336+/* The standard init function */337+static int __init p9_virtio_init(void)338+{339+ int count;340+341+ for (count = 0; count < MAX_9P_CHAN; count++)342+ channels[count].initialized = false;343+344+ v9fs_register_trans(&p9_virtio_trans);345+ return register_virtio_driver(&p9_virtio_drv);346+}347+348+module_init(p9_virtio_init);349+350+MODULE_DEVICE_TABLE(virtio, id_table);351+MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");352+MODULE_DESCRIPTION("Virtio 9p Transport");353+MODULE_LICENSE("GPL");