Hi,

This patch adds the qemu side of the 9P over PCI transport that is
used to implement paravirtualized file system support for KVM/QEMU. In
order to compile the PCI device, you need to download and install the
spfs library (http://sourceforge.net/projects/npfs).

The kernel side of the transport was already sent to the list by Eric
Van Hensbergen.

Any comments and suggestions are appreciated.

Thanks,
    Lucho

diff -ubr --new-file kvm-35.orig/configure kvm-35/configure
--- kvm-35.orig/configure       2007-08-14 21:17:30.000000000 -0600
+++ kvm-35/configure    2007-08-17 17:05:52.000000000 -0600
@@ -86,6 +86,7 @@
     --extra-ldflags="-L $PWD/../user" \
     --enable-kvm --kernel-path="$libkvm_kerneldir" \
     --enable-alsa \
+    --enable-pci-9p \
     ${disable_gcc_check:+"--disable-gcc-check"} \
     --prefix="$prefix"
 )
diff -ubr --new-file kvm-35.orig/qemu/configure kvm-35/qemu/configure
--- kvm-35.orig/qemu/configure  2007-08-14 21:17:30.000000000 -0600
+++ kvm-35/qemu/configure       2007-08-17 11:05:47.000000000 -0600
@@ -262,6 +262,8 @@
   ;;
   --enable-uname-release=*) uname_release="$optarg"
   ;;
+  --enable-pci-9p) pci_9p="yes"
+  ;;
   esac
 done

@@ -589,6 +591,14 @@
 bindir="$prefix/bin"
 fi

+# Check if libspfs is present
+if test "$pci_9p" = "yes" ; then
+    if ! test -f /usr/local/include/spfs.h ; then
+       unset pci_9p
+    fi
+    libspfs_path=/usr/local
+fi
+
 echo "Install prefix    $prefix"
 echo "BIOS directory    $datadir"
 echo "binary directory  $bindir"
@@ -996,6 +1006,12 @@

 done # for target in $targets

+if test "$pci_9p" = "yes" ; then
+       echo "LIBSPFS_PATH=$libspfs_path" >> $config_mak
+       echo "CONFIG_PCI_9P=yes" >> $config_mak
+       echo "#define CONFIG_PCI_9P" >> $config_h
+fi
+
 # build tree in object directory if source path is different from current one
 if test "$source_path_used" = "yes" ; then
     DIRS="tests"
diff -ubr --new-file kvm-35.orig/qemu/hw/9p.c kvm-35/qemu/hw/9p.c
--- kvm-35.orig/qemu/hw/9p.c    1969-12-31 17:00:00.000000000 -0700
+++ kvm-35/qemu/hw/9p.c 2007-08-27 10:41:14.000000000 -0600
@@ -0,0 +1,305 @@
+#include "vl.h"
+#include <stddef.h>
+#include <pthread.h>
+
+#ifdef CONFIG_PCI_9P
+
+#include <spfs.h>
+
+#define IOSIZE 8
+#define MSIZE  64*1024
+
+//#define DPRINTK(format, arg...)      printf(format, ##arg)
+#define DPRINTK(format, arg...)        
+
+extern int npfs_init(Spsrv *srv);
+
+typedef struct P9pci P9pci;
+
+struct P9pci {
+       PCIDevice       dev;
+       uint32_t        ioaddr;
+       uint32_t        tx;
+       uint32_t        rx;
+       int             msize;
+       Spconn*         conn;
+};
+
+static Spsrv *p9_srv;
+static int debug = 0;
+
+static pthread_mutex_t p9_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t p9_wlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t p9_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t p9_thread;
+static Spreq *p9_reqfirst;
+static Spreq *p9_reqlast;
+
+static void p9_io_map(PCIDevice *pdev, int region, uint32_t addr,
uint32_t size, int type);
+static void p9_mem_map(PCIDevice *pdev, int region, uint32_t addr,
uint32_t size, int type);
+static void p9_io_write(void *a, uint32_t addr, uint32_t val);
+static uint32_t p9_io_read(void *a, uint32_t addr);
+
+Spconn *p9pci_conn_create(Spsrv *srv, P9pci *p);
+int p9pci_conn_shutdown(Spconn *conn);
+void p9pci_conn_dataout(Spconn *conn, Spreq *req);
+static void p9pci_conn_out(Spconn *conn);
+
+void *p9pci_request_loop(void *a);
+Spsrv* p9pci_srv_create();
+static void p9pci_srv_start(Spsrv *srv);
+static void p9pci_srv_shutdown(Spsrv *srv);
+static void p9pci_srv_destroy(Spsrv *srv);
+
+void pci_9p_init(PCIBus *bus)
+{
+       uint32_t devid;
+       uint8_t *pcf;
+       char name[32];
+       P9pci *p9dev;
+
+       DPRINTK("pci_p9_init start\n");
+       snprintf(name, sizeof(name), "9P2000");
+       p9dev = (P9pci *) pci_register_device(bus, name, sizeof(*p9dev), -1,
NULL, NULL);
+       if (!p9dev)
+               return;
+
+       devid = 13;
+       pcf = p9dev->dev.config;
+       pcf[0x00] = 0x02;
+       pcf[0x01] = 0x50;
+       pcf[0x02] = devid & 0xFF;
+       pcf[0x03] = (devid >> 8) & 0xFF;
+       pcf[0x09] = 0x00;
+       pcf[0x0a] = 0x00;
+       pcf[0x0e] = 0x00;
+       pcf[0x3d] = 0x01;
+
+       pci_register_io_region(&p9dev->dev, 0, IOSIZE, PCI_ADDRESS_SPACE_IO,
p9_io_map);
+       pci_register_io_region(&p9dev->dev, 1, MSIZE, PCI_ADDRESS_SPACE_MEM,
p9_mem_map);
+       pci_register_io_region(&p9dev->dev, 2, MSIZE, PCI_ADDRESS_SPACE_MEM,
p9_mem_map);
+
+       pthread_create(&p9_thread, NULL, p9pci_request_loop, NULL);
+       p9_srv = p9pci_srv_create();
+       npfs_init(p9_srv);
+       p9dev->conn = p9pci_conn_create(p9_srv, p9dev);
+       DPRINTK("pci_p9_init end\n");
+}
+
+static void
+p9_io_map(PCIDevice *pdev, int region, uint32_t addr, uint32_t size, int type)
+{
+       P9pci *p9dev;
+
+       DPRINTK("p9_io_map addr %x size %d\n", addr, size);
+       p9dev = (P9pci *) pdev;
+       p9dev->ioaddr = addr;
+
+       register_ioport_write(addr, 8, 4, p9_io_write, pdev);
+       register_ioport_read(addr, 8, 4, p9_io_read, pdev);
+}
+
+static void
+p9_mem_map(PCIDevice *pdev, int region, uint32_t addr, uint32_t size, int type)
+{
+       P9pci *p9dev;
+
+       DPRINTK("p9_mem_map addr %x size %d\n", addr, size);
+       p9dev = (P9pci *) pdev;
+       if (region == 1) {
+               p9dev->rx = addr;
+               cpu_register_physical_memory(addr, size, 0x10000);
+       } else {
+               p9dev->tx = addr;
+               cpu_register_physical_memory(addr, size, 0x40000);
+       }
+
+       p9dev->msize = size;
+}
+
+static void
+p9_io_write(void *a, uint32_t addr, uint32_t val)
+{
+       P9pci *p9dev;
+       Spconn *conn;
+       Spfcall *fc;
+       Spreq *req;
+
+       p9dev = a;
+       conn = p9dev->conn;
+       DPRINTK("p9_io_write dev %p addr %x val %d\n", p9dev, addr, val);
+       if (addr == p9dev->ioaddr + 4) {
+               DPRINTK("p9_io_write irq off txlen %x rxlen %x\n",
ldl_phys(p9dev->tx), ldl_phys(p9dev->rx));
+               pci_set_irq(&p9dev->dev, 0, 0);
+               p9pci_conn_out(conn);
+               return;
+       }
+
+       fc = sp_conn_new_incall(conn);
+       fc->size = 0;
+       req = sp_req_alloc(conn, fc);
+       fc = req->tcall;
+       cpu_physical_memory_read(p9dev->rx, fc->pkt, val);
+       stl_phys(p9dev->rx, 0);
+       sp_deserialize(fc, fc->pkt, conn->dotu);
+       if (debug) {
+               fprintf(stderr, "<<< ");
+               sp_printfcall(stderr, fc, conn->dotu);
+               fprintf(stderr, "\n");
+       }
+
+       pthread_mutex_lock(&p9_lock);
+       req->tag = req->tcall->tag;
+       req->next = NULL;
+       if (p9_reqlast)
+               p9_reqlast->next = req;
+       else
+               p9_reqfirst = req;
+
+       p9_reqlast = req;
+       pthread_cond_signal(&p9_cond);
+       pthread_mutex_unlock(&p9_lock);
+}
+
+static uint32_t
+p9_io_read(void *a, uint32_t addr)
+{
+       P9pci *p9dev;
+
+       p9dev = a;
+       DPRINTK("p9_io_write dev %p addr %x\n", p9dev, addr);
+       return 0;
+}
+
+void *
+p9pci_request_loop(void *a)
+{
+       Spreq *req;
+
+       pthread_mutex_lock(&p9_lock);
+       while (1) {
+               req = p9_reqfirst;
+               if (!req) {
+                       pthread_cond_wait(&p9_cond, &p9_lock);
+                       continue;
+               }
+
+               p9_reqfirst = req->next;
+               if (!p9_reqfirst)
+                       p9_reqlast = NULL;
+
+               pthread_mutex_unlock(&p9_lock);
+               req->next = NULL;
+               sp_srv_process_req(req);
+               pthread_mutex_lock(&p9_lock);
+       }
+       pthread_mutex_unlock(&p9_lock);
+}
+
+Spconn*
+p9pci_conn_create(Spsrv *srv, P9pci *p)
+{
+       Spconn *conn;
+
+       DPRINTK("p9pci_conn_create\n");
+       conn = sp_conn_create(srv);
+       if (!conn)
+               return NULL;
+
+       conn->caux = p;
+       conn->shutdown = p9pci_conn_shutdown;
+       conn->dataout = p9pci_conn_dataout;
+       sp_srv_add_conn(srv, conn);
+       return conn;
+}
+
+int
+p9pci_conn_shutdown(Spconn *conn)
+{
+       DPRINTK("p9pci_conn_shutdown\n");
+       return 1;
+}
+
+void
+p9pci_conn_dataout(Spconn *conn, Spreq *req)
+{
+       P9pci *p;
+
+       p = conn->caux;
+       DPRINTK("p9pci_conn_dataout req %p txlen %d\n", req, ldl_phys(p->tx));
+       if (req != conn->oreqs) {
+               DPRINTK("p9pci_conn_dataout: not first\n");
+               return;
+       }
+
+       p9pci_conn_out(conn);
+}
+
+static void
+p9pci_conn_out(Spconn *conn)
+{
+       Spreq *req;
+       P9pci *p;
+
+       pthread_mutex_lock(&p9_wlock);
+       p = conn->caux;
+       if (ldl_phys(p->tx))
+               goto done;
+
+       req = conn->oreqs;
+       if (!req)
+               goto done;
+
+       if (debug) {
+               fprintf(stderr, ">>> ");
+               sp_printfcall(stderr, req->rcall, conn->dotu);
+               fprintf(stderr, "\n");
+       }
+
+       cpu_physical_memory_write(p->tx, req->rcall->pkt, req->rcall->size);
+       conn->oreqs = req->next;
+       sp_conn_free_incall(conn, req->tcall);
+       free(req->rcall);
+       sp_req_free(req);
+       pci_set_irq(&p->dev, 0, 1);
+done:
+       pthread_mutex_unlock(&p9_wlock);
+}
+
+Spsrv*
+p9pci_srv_create()
+{
+       Spsrv *srv;
+
+       DPRINTK("pci_srv_create\n");
+       srv = sp_srv_create();
+       if (!srv) {
+               return NULL;
+       }
+
+       srv->start = p9pci_srv_start;
+       srv->shutdown = p9pci_srv_shutdown;
+       srv->destroy = p9pci_srv_destroy;
+
+       return srv;
+}
+
+static void
+p9pci_srv_start(Spsrv *srv)
+{
+       DPRINTK("pci_srv_start\n");
+}
+
+static void
+p9pci_srv_shutdown(Spsrv *srv)
+{
+       DPRINTK("pci_srv_shutdown\n");
+}
+
+static void
+p9pci_srv_destroy(Spsrv *srv)
+{
+       DPRINTK("pci_srv_destroy\n");
+//     free(srv->srvaux);
+}
+#endif
diff -ubr --new-file kvm-35.orig/qemu/hw/pc.c kvm-35/qemu/hw/pc.c
--- kvm-35.orig/qemu/hw/pc.c    2007-08-14 21:17:30.000000000 -0600
+++ kvm-35/qemu/hw/pc.c 2007-08-17 10:48:37.000000000 -0600
@@ -739,6 +739,9 @@
 #ifdef USE_HYPERCALL
     pci_hypercall_init(pci_bus);
 #endif
+#ifdef CONFIG_PCI_9P
+    pci_9p_init(pci_bus);
+#endif
     if (pci_enabled) {
         pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
     } else {
diff -ubr --new-file kvm-35.orig/qemu/hw/ufs.c kvm-35/qemu/hw/ufs.c
--- kvm-35.orig/qemu/hw/ufs.c   1969-12-31 17:00:00.000000000 -0700
+++ kvm-35/qemu/hw/ufs.c        2007-08-25 22:03:42.000000000 -0600
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2005 by Latchesar Ionkov <[EMAIL PROTECTED]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+//#define _XOPEN_SOURCE 500
+#define _BSD_SOURCE
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <utime.h>
+#include "config.h"
+
+#ifdef CONFIG_PCI_9P
+#include <spfs.h>
+
+#define NELEM(x)       (sizeof(x)/sizeof((x)[0]))
+
+typedef struct Fid Fid;
+
+struct Fid {
+       char*           path;
+       int             omode;
+       int             fd;
+       DIR*            dir;
+       int             diroffset;
+       char*           direntname;
+       struct stat     stat;
+};
+
+int sameuser = 1;
+
+char *Estatfailed = "stat failed";
+char *Ebadfid = "fid unknown or out of range";
+char *Enoextension = "empty extension while creating special file";
+char *Eformat = "incorrect extension format";
+char *Ecreatesocket = "cannot create socket";
+//char *E = "";
+
+static int fidstat(Fid *fid);
+static void ustat2qid(struct stat *st, Spqid *qid);
+static u8 ustat2qidtype(struct stat *st);
+static u32 umode2npmode(mode_t umode, int dotu);
+static mode_t npstat2umode(Spstat *st, int dotu);
+static void ustat2npwstat(char *path, struct stat *st, Spwstat
*wstat, int dotu);
+
+static Spfcall* npfs_attach(Spfid *fid, Spfid *afid, Spstr *uname,
Spstr *aname, u32 n_uname);
+static int npfs_clone(Spfid *fid, Spfid *newfid);
+static int npfs_walk(Spfid *fid, Spstr *wname, Spqid *wqid);
+static Spfcall* npfs_open(Spfid *fid, u8 mode);
+static Spfcall* npfs_create(Spfid *fid, Spstr *name, u32 perm, u8 mode,
+       Spstr *extension);
+static Spfcall* npfs_read(Spfid *fid, u64 offset, u32 count, Spreq *);
+static Spfcall* npfs_write(Spfid *fid, u64 offset, u32 count, u8
*data, Spreq *);
+static Spfcall* npfs_clunk(Spfid *fid);
+static Spfcall* npfs_remove(Spfid *fid);
+static Spfcall* npfs_stat(Spfid *fid);
+static Spfcall* npfs_wstat(Spfid *fid, Spstat *stat);
+
+static void npfs_fiddestroy(Spfid *fid);
+
+int
+npfs_init(Spsrv *srv)
+{
+       srv->dotu = 1;
+       srv->msize = 65536;
+       srv->debuglevel = 1;
+       srv->attach = npfs_attach;
+       srv->clone = npfs_clone;
+       srv->walk = npfs_walk;
+       srv->open = npfs_open;
+       srv->create = npfs_create;
+       srv->read = npfs_read;
+       srv->write = npfs_write;
+       srv->clunk = npfs_clunk;
+       srv->remove = npfs_remove;
+       srv->stat = npfs_stat;
+       srv->wstat = npfs_wstat;
+       srv->fiddestroy = npfs_fiddestroy;
+
+       return 1;
+}
+
+static int
+fidstat(Fid *fid)
+{
+       if (lstat(fid->path, &fid->stat) < 0)
+               return errno;
+
+       if (S_ISDIR(fid->stat.st_mode))
+               fid->stat.st_size = 0;
+
+       return 0;
+}
+
+static Fid*
+npfs_fidalloc() {
+       Fid *f;
+
+       f = malloc(sizeof(*f));
+
+       f->path = NULL;
+       f->omode = -1;
+       f->fd = -1;
+       f->dir = NULL;
+       f->diroffset = 0;
+       f->direntname = NULL;
+
+       return f;
+}
+
+static void
+npfs_fiddestroy(Spfid *fid)
+{
+       Fid *f;
+
+       f = fid->aux;
+       if (!f)
+               return;
+
+       if (f->fd != -1)
+               close(f->fd);
+
+       if (f->dir)
+               closedir(f->dir);
+
+       free(f->path);
+       free(f);
+}
+
+static void
+create_rerror(int ecode)
+{
+       char *s, buf[256];
+
+       s = strerror_r(ecode, buf, sizeof(buf));
+       sp_werror(s, ecode);
+}
+
+static int
+omode2uflags(u8 mode)
+{
+       int ret;
+
+       ret = 0;
+       switch (mode & 3) {
+       case Oread:
+               ret = O_RDONLY;
+               break;
+
+       case Ordwr:
+               ret = O_RDWR;
+               break;
+
+       case Owrite:
+               ret = O_WRONLY;
+               break;
+
+       case Oexec:
+               ret = O_RDONLY;
+               break;
+       }
+
+       if (mode & Otrunc)
+               ret |= O_TRUNC;
+
+       if (mode & Oappend)
+               ret |= O_APPEND;
+
+       if (mode & Oexcl)
+               ret |= O_EXCL;
+
+       return ret;
+}
+
+static void
+ustat2qid(struct stat *st, Spqid *qid)
+{
+       int n;
+
+       qid->path = 0;
+       n = sizeof(qid->path);
+       if (n > sizeof(st->st_ino))
+               n = sizeof(st->st_ino);
+       memmove(&qid->path, &st->st_ino, n);
+       qid->version = st->st_mtime ^ (st->st_size << 8);
+       qid->type = ustat2qidtype(st);
+}
+
+static u8
+ustat2qidtype(struct stat *st)
+{
+       u8 ret;
+
+       ret = 0;
+       if (S_ISDIR(st->st_mode))
+               ret |= Qtdir;
+
+       if (S_ISLNK(st->st_mode))
+               ret |= Qtsymlink;
+
+       return ret;
+}
+
+static u32
+umode2npmode(mode_t umode, int dotu)
+{
+       u32 ret;
+
+       ret = umode & 0777;
+       if (S_ISDIR(umode))
+               ret |= Dmdir;
+
+       if (dotu) {
+               if (S_ISLNK(umode))
+                       ret |= Dmsymlink;
+               if (S_ISSOCK(umode))
+                       ret |= Dmsocket;
+               if (S_ISFIFO(umode))
+                       ret |= Dmnamedpipe;
+               if (S_ISBLK(umode))
+                       ret |= Dmdevice;
+               if (S_ISCHR(umode))
+                       ret |= Dmdevice;
+               if (umode & S_ISUID)
+                       ret |= Dmsetuid;
+               if (umode & S_ISGID)
+                       ret |= Dmsetgid;
+       }
+
+       return ret;
+}
+
+static mode_t
+np2umode(u32 mode, Spstr *extension, int dotu)
+{
+       mode_t ret;
+
+       ret = mode & 0777;
+       if (mode & Dmdir)
+               ret |= S_IFDIR;
+
+       if (dotu) {
+               if (mode & Dmsymlink)
+                       ret |= S_IFLNK;
+               if (mode & Dmsocket)
+                       ret |= S_IFSOCK;
+               if (mode & Dmnamedpipe)
+                       ret |= S_IFIFO;
+               if (mode & Dmdevice) {
+                       if (extension && extension->str[0] == 'c')
+                               ret |= S_IFCHR;
+                       else
+                               ret |= S_IFBLK;
+               }
+       }
+
+       if (!(ret&~0777))
+               ret |= S_IFREG;
+
+       if (mode & Dmsetuid)
+               ret |= S_ISUID;
+       if (mode & Dmsetgid)
+               ret |= S_ISGID;
+
+       return ret;
+}
+
+static mode_t
+npstat2umode(Spstat *st, int dotu)
+{
+       return np2umode(st->mode, &st->extension, dotu);
+}
+
+static void
+ustat2npwstat(char *path, struct stat *st, Spwstat *wstat, int dotu)
+{
+       int err;
+       Spuser *u;
+       Spgroup *g;
+       char *s, ext[256];
+
+       memset(wstat, 0, sizeof(*wstat));
+       ustat2qid(st, &wstat->qid);
+       wstat->mode = umode2npmode(st->st_mode, dotu);
+       wstat->atime = st->st_atime;
+       wstat->mtime = st->st_mtime;
+       wstat->length = st->st_size;
+
+       u = sp_uid2user(st->st_uid);
+       g = sp_gid2group(st->st_gid);
+       
+       wstat->uid = u?u->uname:"???";
+       wstat->gid = g?g->gname:"???";
+       wstat->muid = "";
+
+       wstat->extension = NULL;
+       if (dotu) {
+               wstat->n_uid = st->st_uid;
+               wstat->n_gid = st->st_gid;
+
+               if (wstat->mode & Dmsymlink) {
+                       err = readlink(path, ext, sizeof(ext) - 1);
+                       if (err < 0)
+                               err = 0;
+
+                       ext[err] = '\0';
+               } else if (wstat->mode & Dmdevice) {
+                       snprintf(ext, sizeof(ext), "%c %u %u",
+                               S_ISCHR(st->st_mode)?'c':'b',
+                               major(st->st_rdev), minor(st->st_rdev));
+               } else {
+                       ext[0] = '\0';
+               }
+
+               wstat->extension = strdup(ext);
+       }
+
+       s = strrchr(path, '/');
+       if (s)
+               wstat->name = s + 1;
+       else
+               wstat->name = path;
+}
+
+static inline void
+npfs_change_user(Spuser *user)
+{
+       if (!sameuser)
+               sp_change_user(user);
+}
+
+static Spfcall*
+npfs_attach(Spfid *nfid, Spfid *nafid, Spstr *uname, Spstr *aname, u32 n_uname)
+{
+       int err;
+       Spfcall* ret;
+       Fid *fid;
+       Spqid qid;
+       char *user;
+
+       user = NULL;
+       ret = NULL;
+
+       if (nafid != NULL) {
+               sp_werror(Enoauth, EIO);
+               goto done;
+       }
+
+       fid = npfs_fidalloc();
+       fid->omode = -1;
+       nfid->user = NULL;
+       if (uname->len) {
+               user = sp_strdup(uname);
+               nfid->user = sp_uname2user(user);
+               free(user);
+       }
+
+       if (!nfid->user) {
+               free(fid);
+               sp_werror(Eunknownuser, EIO);
+               goto done;
+       }
+       npfs_change_user(nfid->user);
+
+       fid->omode = -1;
+       if (aname->len==0 || *aname->str!='/')
+               fid->path = strdup("/");
+       else
+               fid->path = sp_strdup(aname);
+       
+       nfid->aux = fid;
+       err = fidstat(fid);
+       if (err < 0) {
+               create_rerror(err);
+               goto done;
+       }
+
+       ustat2qid(&fid->stat, &qid);
+       ret = sp_create_rattach(&qid);
+       sp_fid_incref(nfid);
+
+done:
+       return ret;
+}
+
+static int
+npfs_clone(Spfid *fid, Spfid *newfid)
+{
+       Fid *f, *nf;
+
+       f = fid->aux;
+       nf = npfs_fidalloc();
+       nf->path = strdup(f->path);
+       newfid->aux = nf;
+
+       return 1;       
+}
+
+
+static int
+npfs_walk(Spfid *fid, Spstr* wname, Spqid *wqid)
+{
+       int n;
+       Fid *f;
+       struct stat st;
+       char *path;
+
+       f = fid->aux;
+       npfs_change_user(fid->user);
+       n = fidstat(f);
+       if (n < 0)
+               create_rerror(n);
+
+       n = strlen(f->path);
+       path = malloc(n + wname->len + 2);
+       memcpy(path, f->path, n);
+       path[n] = '/';
+       memcpy(path + n + 1, wname->str, wname->len);
+       path[n + wname->len + 1] = '\0';
+
+       if (lstat(path, &st) < 0) {
+               free(path);
+               create_rerror(errno);
+               return 0;
+       }
+
+       free(f->path);
+       f->path = path;
+       ustat2qid(&st, wqid);
+
+       return 1;
+}
+
+static Spfcall*
+npfs_open(Spfid *fid, u8 mode)
+{
+       int err;
+       Fid *f;
+       Spqid qid;
+
+       f = fid->aux;
+       npfs_change_user(fid->user);
+       if ((err = fidstat(f)) < 0)
+               create_rerror(err);
+
+       if (S_ISDIR(f->stat.st_mode)) {
+               f->dir = opendir(f->path);
+               if (!f->dir)
+                       create_rerror(errno);
+       } else {
+               f->fd = open(f->path, omode2uflags(mode));
+               if (f->fd < 0)
+                       create_rerror(errno);
+       }
+
+       err = fidstat(f);
+       if (err < 0)
+               create_rerror(err);
+
+       f->omode = mode;
+       ustat2qid(&f->stat, &qid);
+       return sp_create_ropen(&qid, 0);
+}
+
+static int
+npfs_create_special(Spfid *fid, char *path, u32 perm, Spstr *extension)
+{
+       int nfid, err;
+       int nmode, major, minor;
+       char ctype;
+       mode_t umode;
+       Spfid *ofid;
+       Fid *f, *of;
+       char *ext;
+
+       f = fid->aux;
+       if (!perm&Dmnamedpipe && !extension->len) {
+               sp_werror(Enoextension, EIO);
+               return -1;
+       }
+
+       umode = np2umode(perm, extension, fid->conn->dotu);
+       ext = sp_strdup(extension);
+       if (perm & Dmsymlink) {
+               if (symlink(ext, path) < 0) {
+                       err = errno;
+                       fprintf(stderr, "symlink %s %s %d\n", ext, path, err);
+                       create_rerror(err);
+                       goto error;
+               }
+       } else if (perm & Dmlink) {
+               if (sscanf(ext, "%d", &nfid) == 0) {
+                       sp_werror(Eformat, EIO);
+                       goto error;
+               }
+
+               ofid = sp_fid_find(fid->conn, nfid);
+               if (!ofid) {
+                       sp_werror(Eunknownfid, EIO);
+                       goto error;
+               }
+
+               of = ofid->aux;
+               if (link(of->path, path) < 0) {
+                       create_rerror(errno);
+                       goto error;
+               }
+       } else if (perm & Dmdevice) {
+               if (sscanf(ext, "%c %u %u", &ctype, &major, &minor) != 3) {
+                       sp_werror(Eformat, EIO);
+                       goto error;
+               }
+
+               nmode = 0;
+               switch (ctype) {
+               case 'c':
+                       nmode = S_IFCHR;
+                       break;
+
+               case 'b':
+                       nmode = S_IFBLK;
+                       break;
+
+               default:
+                       sp_werror(Eformat, EIO);
+                       goto error;
+               }
+
+               nmode |= perm & 0777;
+               if (mknod(path, nmode, makedev(major, minor)) < 0) {
+                       create_rerror(errno);
+                       goto error;
+               }
+       } else if (perm & Dmnamedpipe) {
+               if (mknod(path, S_IFIFO | (umode&0777), 0) < 0) {
+                       create_rerror(errno);
+                       goto error;
+               }
+       }
+
+       f->omode = 0;
+       if (!perm&Dmsymlink && chmod(path, umode)<0) {
+               create_rerror(errno);
+               goto error;
+       }
+
+       free(ext);
+       return 0;
+
+error:
+       free(ext);
+       return -1;
+}
+
+
+static Spfcall*
+npfs_create(Spfid *fid, Spstr *name, u32 perm, u8 mode, Spstr *extension)
+{
+       int n, err, omode;
+       Fid *f;
+       Spfcall *ret;
+       Spqid qid;
+       char *npath;
+       struct stat st;
+
+       ret = NULL;
+       omode = mode;
+       f = fid->aux;
+       if ((err = fidstat(f)) < 0)
+               create_rerror(err);
+
+       n = strlen(f->path);
+       npath = malloc(n + name->len + 2);
+       memmove(npath, f->path, n);
+       npath[n] = '/';
+       memmove(npath + n + 1, name->str, name->len);
+       npath[n + name->len + 1] = '\0';
+
+       if (lstat(npath, &st)==0 || errno!=ENOENT) {
+               sp_werror(Eexist, EEXIST);
+               goto out;
+       }
+
+       if (perm & Dmdir) {
+               if (mkdir(npath, perm & 0777) < 0) {
+                       create_rerror(errno);
+                       goto out;
+               }
+
+               if (lstat(npath, &f->stat) < 0) {
+                       create_rerror(errno);
+                       rmdir(npath);
+                       goto out;
+               }
+               
+               f->dir = opendir(npath);
+               if (!f->dir) {
+                       create_rerror(errno);
+                       remove(npath);
+                       goto out;
+               }
+       } else if (perm & (Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice)) {
+               if (npfs_create_special(fid, npath, perm, extension) < 0)
+                       goto out;
+
+               if (lstat(npath, &f->stat) < 0) {
+                       create_rerror(errno);
+                       remove(npath);
+                       goto out;
+               }
+       } else {
+               f->fd = open(npath, O_CREAT|omode2uflags(mode),
+                       perm & 0777);
+               if (f->fd < 0) {
+                       create_rerror(errno);
+                       goto out;
+               }
+
+               if (lstat(npath, &f->stat) < 0) {
+                       create_rerror(errno);
+                       remove(npath);
+                       goto out;
+               }
+       }
+
+       free(f->path);
+       f->path = npath;
+       f->omode = omode;
+       npath = NULL;
+       ustat2qid(&f->stat, &qid);
+       ret = sp_create_rcreate(&qid, 0);
+
+out:
+       free(npath);
+       return ret;
+}
+
+static u32
+npfs_read_dir(Fid *f, u8* buf, u64 offset, u32 count, int dotu)
+{
+       int i, n, plen;
+       char *dname, *path;
+       struct dirent *dirent;
+       struct stat st;
+       Spwstat wstat;
+
+       if (offset == 0) {
+               rewinddir(f->dir);
+               f->diroffset = 0;
+       }
+
+       plen = strlen(f->path);
+       n = 0;
+       dirent = NULL;
+       dname = f->direntname;
+       while (n < count) {
+               if (!dname) {
+                       dirent = readdir(f->dir);
+                       if (!dirent)
+                               break;
+
+                       if (strcmp(dirent->d_name, ".") == 0
+                       || strcmp(dirent->d_name, "..") == 0)
+                               continue;
+
+                       dname = dirent->d_name;
+               }
+
+               path = malloc(plen + strlen(dname) + 2);
+               sprintf(path, "%s/%s", f->path, dname);
+               
+               if (lstat(path, &st) < 0) {
+                       free(path);
+                       create_rerror(errno);
+                       return 0;
+               }
+
+               ustat2npwstat(path, &st, &wstat, dotu);
+               i = sp_serialize_stat(&wstat, buf + n, count - n - 1, dotu);
+               free(wstat.extension);
+               free(path);
+               path = NULL;
+               if (i==0)
+                       break;
+
+               dname = NULL;
+               n += i;
+       }
+
+       if (f->direntname) {
+               free(f->direntname);
+               f->direntname = NULL;
+       }
+
+       if (dirent)
+               f->direntname = strdup(dirent->d_name);
+
+       f->diroffset += n;
+       return n;
+}
+
+static Spfcall*
+npfs_read(Spfid *fid, u64 offset, u32 count, Spreq *req)
+{
+       int n;
+       Fid *f;
+       Spfcall *ret;
+
+       f = fid->aux;
+       ret = sp_alloc_rread(count);
+       npfs_change_user(fid->user);
+       if (f->dir)
+               n = npfs_read_dir(f, ret->data, offset, count, fid->conn->dotu);
+       else {
+               n = pread(f->fd, ret->data, count, offset);
+               if (n < 0)
+                       create_rerror(errno);
+       }
+
+       if (sp_haserror()) {
+               free(ret);
+               ret = NULL;
+       } else
+               sp_set_rread_count(ret, n);
+
+       return ret;
+}
+
+static Spfcall*
+npfs_write(Spfid *fid, u64 offset, u32 count, u8 *data, Spreq *req)
+{
+       int n;
+       Fid *f;
+
+       f = fid->aux;
+       npfs_change_user(fid->user);
+
+       n = pwrite(f->fd, data, count, offset);
+       if (n < 0)
+               create_rerror(errno);
+
+       return sp_create_rwrite(n);
+}
+
+static Spfcall*
+npfs_clunk(Spfid *fid)
+{
+       Fid *f;
+       Spfcall *ret;
+
+       f = fid->aux;
+       ret = sp_create_rclunk();
+//     sp_fid_decref(fid);
+       return ret;
+}
+
+static Spfcall*
+npfs_remove(Spfid *fid)
+{
+       Fid *f;
+       Spfcall *ret;
+
+       ret = NULL;
+       f = fid->aux;
+       npfs_change_user(fid->user);
+       if (remove(f->path) < 0) {
+               create_rerror(errno);
+               goto out;
+       }
+
+       ret = sp_create_rremove();
+
+out:
+//     sp_fid_decref(fid);
+       return ret;
+
+}
+
+static Spfcall*
+npfs_stat(Spfid *fid)
+{
+       int err;
+       Fid *f;
+       Spfcall *ret;
+       Spwstat wstat;
+
+       f = fid->aux;
+       npfs_change_user(fid->user);
+       err = fidstat(f);
+       if (err < 0)
+               create_rerror(err);
+
+       ustat2npwstat(f->path, &f->stat, &wstat, fid->conn->dotu);
+
+       ret = sp_create_rstat(&wstat, fid->conn->dotu);
+       free(wstat.extension);
+
+       return ret;
+}
+
+static Spfcall*
+npfs_wstat(Spfid *fid, Spstat *stat)
+{
+       int err;
+       Fid *f;
+       Spfcall *ret;
+       uid_t uid;
+       gid_t gid;
+       char *npath, *p, *s;
+       Spuser *user;
+       Spgroup *group;
+       struct utimbuf tb;
+
+       ret = NULL;
+       f = fid->aux;
+       npfs_change_user(fid->user);
+       err = fidstat(f);
+       if (err < 0) {
+               create_rerror(err);
+               goto out;
+       }
+
+       if (fid->conn->dotu) {
+               uid = stat->n_uid;
+               gid = stat->n_gid;
+       } else {
+               uid = (uid_t) -1;
+               gid = (gid_t) -1;
+       }
+
+       if (uid == -1 && stat->uid.len) {
+               s = sp_strdup(&stat->uid);
+               user = sp_uname2user(s);
+               free(s);
+               if (!user) {
+                       sp_werror(Eunknownuser, EIO);
+                       goto out;
+               }
+
+               uid = user->uid;
+       }
+
+       if (gid == -1 && stat->gid.len) {
+               s = sp_strdup(&stat->gid);
+               group = sp_gname2group(s);
+               free(s);
+               if (!group) {
+                       sp_werror(Eunknownuser, EIO);
+                       goto out;
+               }
+
+               gid = group->gid;
+       }
+
+       if (stat->mode != (u32)~0) {
+               if (stat->mode&Dmdir && !S_ISDIR(f->stat.st_mode)) {
+                       sp_werror(Edirchange, EIO);
+                       goto out;
+               }
+
+               if (chmod(f->path, npstat2umode(stat, fid->conn->dotu)) < 0) {
+                       create_rerror(errno);
+                       goto out;
+               }
+       }
+
+       if (stat->mtime != (u32)~0) {
+               tb.actime = 0;
+               tb.modtime = stat->mtime;
+               if (utime(f->path, &tb) < 0) {
+                       create_rerror(errno);
+                       goto out;
+               }
+       }
+
+       if (gid != -1) {
+               if (chown(f->path, uid, gid) < 0) {
+                       create_rerror(errno);
+                       goto out;
+               }
+       }
+
+       if (stat->name.len != 0) {
+               p = strrchr(f->path, '/');
+               if (!p)
+                       p = f->path + strlen(f->path);
+
+               npath = malloc(stat->name.len + (p - f->path) + 2);
+               memcpy(npath, f->path, p - f->path);
+               npath[p - f->path] = '/';
+               memcpy(npath + (p - f->path) + 1, stat->name.str, 
stat->name.len);
+               npath[(p - f->path) + 1 + stat->name.len] = 0;
+               if (strcmp(npath, f->path) != 0) {
+                       if (rename(f->path, npath) < 0) {
+                               create_rerror(errno);
+                               goto out;
+                       }
+
+                       free(f->path);
+                       f->path = npath;
+               }
+       }
+
+       if (stat->length != ~0) {
+               if (truncate(f->path, stat->length) < 0) {
+                       create_rerror(errno);
+                       goto out;
+               }
+       }
+       ret = sp_create_rwstat();
+       
+out:
+       return ret;
+}
+
+#endif
diff -ubr --new-file kvm-35.orig/qemu/Makefile.target
kvm-35/qemu/Makefile.target
--- kvm-35.orig/qemu/Makefile.target    2007-08-14 21:17:30.000000000 -0600
+++ kvm-35/qemu/Makefile.target 2007-08-17 11:04:16.000000000 -0600
@@ -377,6 +377,9 @@
 # PCI Hypercall
 VL_OBJS+= hypercall.o

+# PCI 9P
+VL_OBJS+= 9p.o ufs.o
+
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
 VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
@@ -461,6 +464,10 @@
 VL_LDFLAGS+=-p
 endif

+ifdef CONFIG_PCI_9P
+VL_LIBS+=-L$(LIBSPFS_PATH)/lib -lspfs
+endif
+
 ifeq ($(ARCH),ia64)
 VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
 endif
diff -ubr --new-file kvm-35.orig/qemu/vl.h kvm-35/qemu/vl.h
--- kvm-35.orig/qemu/vl.h       2007-08-14 21:17:30.000000000 -0600
+++ kvm-35/qemu/vl.h    2007-08-17 10:12:59.000000000 -0600
@@ -1247,6 +1247,9 @@
 void pci_hypercall_init(PCIBus *bus);
 void vmchannel_init(CharDriverState *hd, uint32_t deviceid, uint32_t index);

+/* 9p.c */
+void pci_9p_init(PCIBus *bus);
+
 /* buf = NULL means polling */
 typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
                               const uint8_t *buf, int len);

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to