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